From c3aac9026951e2a6e35e76b9c7d36e114a281453 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Tue, 5 May 2026 00:43:54 +0200 Subject: Remove old api and move api-test content to src and include dirs --- include/api-test/buffer.hpp | 18 -- include/api-test/dx12-command-buffer.hpp | 28 --- include/api-test/dx12-device-types.hpp | 74 ------- include/api-test/dx12-device.hpp | 97 ---------- include/api-test/freelist.hpp | 151 --------------- include/api-test/handle.hpp | 24 --- include/api-test/resource-manager.hpp | 22 --- include/api-test/texture.hpp | 17 -- include/api-test/vk-bindless.hpp | 93 --------- include/api-test/vk-command-buffer.hpp | 103 ---------- include/api-test/vk-device-types.hpp | 213 -------------------- include/api-test/vk-device.hpp | 161 ---------------- include/api-test/vk-utils.hpp | 16 -- include/buffer.hpp | 18 ++ include/bvh-node.hpp | 320 ------------------------------- include/compute-renderpass.hpp | 41 ---- include/dx12-command-buffer.hpp | 28 +++ include/dx12-device-types.hpp | 74 +++++++ include/dx12-device.hpp | 97 ++++++++++ include/freelist.hpp | 158 +++++++++++++++ include/handle.hpp | 13 ++ include/primitive-renderpass.hpp | 93 --------- include/renderpass.hpp | 22 --- include/texture.hpp | 86 +-------- include/vk-api.hpp | 219 --------------------- include/vk-bindless.hpp | 49 +++++ include/vk-command-buffer.hpp | 75 ++++++++ include/vk-context.hpp | 49 ----- include/vk-device-types.hpp | 218 +++++++++++++++++++++ include/vk-device.hpp | 163 ++++++++++++++++ include/vk-renderer.hpp | 164 ---------------- include/vk-utils.hpp | 12 ++ 32 files changed, 915 insertions(+), 2001 deletions(-) delete mode 100644 include/api-test/buffer.hpp delete mode 100644 include/api-test/dx12-command-buffer.hpp delete mode 100644 include/api-test/dx12-device-types.hpp delete mode 100644 include/api-test/dx12-device.hpp delete mode 100644 include/api-test/freelist.hpp delete mode 100644 include/api-test/handle.hpp delete mode 100644 include/api-test/resource-manager.hpp delete mode 100644 include/api-test/texture.hpp delete mode 100644 include/api-test/vk-bindless.hpp delete mode 100644 include/api-test/vk-command-buffer.hpp delete mode 100644 include/api-test/vk-device-types.hpp delete mode 100644 include/api-test/vk-device.hpp delete mode 100644 include/api-test/vk-utils.hpp create mode 100644 include/buffer.hpp delete mode 100644 include/bvh-node.hpp delete mode 100644 include/compute-renderpass.hpp create mode 100644 include/dx12-command-buffer.hpp create mode 100644 include/dx12-device-types.hpp create mode 100644 include/dx12-device.hpp create mode 100644 include/freelist.hpp create mode 100644 include/handle.hpp delete mode 100644 include/primitive-renderpass.hpp delete mode 100644 include/renderpass.hpp delete mode 100644 include/vk-api.hpp create mode 100644 include/vk-bindless.hpp create mode 100644 include/vk-command-buffer.hpp delete mode 100644 include/vk-context.hpp create mode 100644 include/vk-device-types.hpp create mode 100644 include/vk-device.hpp delete mode 100644 include/vk-renderer.hpp create mode 100644 include/vk-utils.hpp (limited to 'include') diff --git a/include/api-test/buffer.hpp b/include/api-test/buffer.hpp deleted file mode 100644 index 64c4881..0000000 --- a/include/api-test/buffer.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -struct device_buffer; - -class buffer { -public: - buffer(handle handle); - -private: - handle handle; - -}; diff --git a/include/api-test/dx12-command-buffer.hpp b/include/api-test/dx12-command-buffer.hpp deleted file mode 100644 index e9de39a..0000000 --- a/include/api-test/dx12-command-buffer.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include "handle.hpp" -#include "dx12-device-types.hpp" - -namespace dx12 { - struct command_buffer { - void start() const; - void stop() const; - - // void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; - - void copy(handle src_buffer, handle dst_texture, uint64_t offset = 0) const; - - ID3D12CommandAllocator* command_allocator; - ID3D12GraphicsCommandList* dx12_command_buffer; - dx12::QueueType queue_type; - }; - - struct graphics_command_buffer: public command_buffer { - // void dispatch(const dispatch_params& params) const; - - // void begin_renderpass(const renderpass_params& params) const; - // void draw(const draw_params& params) const; - // void draw_indexed(const draw_indexed_params& params) const; - // void end_renderpass() const; - }; -} diff --git a/include/api-test/dx12-device-types.hpp b/include/api-test/dx12-device-types.hpp deleted file mode 100644 index 4b2fc42..0000000 --- a/include/api-test/dx12-device-types.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#include -#include -#include - -#include - -namespace dx12 { - enum class QueueType : uint32_t { - GRAPHICS, - ASYNC_COMPUTE, - TRANSFER, - MAX, - }; - - struct buffer_desc { - uint32_t size; - bool map; - - D3D12_RESOURCE_STATES states; - D3D12_RESOURCE_FLAGS usages; - D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_DEFAULT; - }; - - struct device_buffer { - ID3D12Resource* resource; - - D3D12MA::Allocation* alloc; - uint32_t size; - void* mapped_ptr = nullptr; - }; - - - struct texture_desc { - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - - D3D12_RESOURCE_STATES states; - D3D12_RESOURCE_FLAGS usages; - DXGI_FORMAT format; - D3D12_RESOURCE_DIMENSION type; - }; - - struct device_texture { - ID3D12Resource* resource; - D3D12MA::Allocation* alloc; - - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - uint64_t row_pitch = 1U; - - DXGI_FORMAT format; - - }; - - struct surface_desc { - HWND window_handle; - DXGI_FORMAT surface_format; - DXGI_SWAP_EFFECT present_mode; - DXGI_USAGE usages; - uint32_t image_count = surface_desc::default_image_count; - - static constexpr uint32_t max_image_count = 3U; - static constexpr uint32_t default_image_count = 3U; - }; - - struct device_surface { - IDXGISwapChain1* swapchain; - }; -} diff --git a/include/api-test/dx12-device.hpp b/include/api-test/dx12-device.hpp deleted file mode 100644 index baa5b60..0000000 --- a/include/api-test/dx12-device.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include -#include - -#include "freelist.hpp" -#include "dx12-device-types.hpp" - -#include "D3D12MemAlloc.h" - -namespace dx12 { - struct command_buffer; - - class device { - struct queue { - ID3D12CommandQueue* dx_queue; - D3D12_COMMAND_LIST_TYPE type; - }; - public: - void init(); - - static inline device& get_render_device() { - return render_device; - } - - handle create_surface(const surface_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - handle create_texture(const texture_desc& desc); - - void create_graphics_pipeline() {}; - - void create_compute_pipeline() {}; - - void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type); - - - [[nodiscard]] inline device_surface& get_surface(handle handle) { - return surfaces[handle]; - } - - [[nodiscard]] inline device_buffer& get_buffer(handle handle) { - return buffers[handle]; - } - - [[nodiscard]] inline device_texture& get_texture(handle handle) { - return textures[handle]; - } - - [[nodiscard]] inline ID3D12Device* get_device() const { - return device; - } - - uint32_t submit(command_buffer* buffers, uint32_t count); - - void wait(); - - private: - IDXGIFactory3* factory; - IDXGIAdapter* adapter; - ID3D12Debug* debug_interface; - - D3D12MA::Allocator* allocator; - - ID3D12Device* device; - ID3D12Fence* fence; - uint64_t fence_value = 0U; - queue queues[static_cast(QueueType::MAX)]; - - freelist surfaces; - freelist buffers; - freelist textures; - - static constexpr size_t max_allocable_command_buffers = 16U; - static constexpr size_t max_submitable_command_buffers = 16U; - - static class device render_device; - - struct bindless_model { - void init(); - - [[nodiscard]] inline ID3D12DescriptorHeap* const* get_heaps() const { - return &resources_heap; - } - - ID3D12DescriptorHeap* resources_heap; - ID3D12DescriptorHeap* samplers_heap; - } model; - - public: - [[nodiscard]] static inline const device::bindless_model& get_bindless_model() { - return render_device.model; - } - }; - -} diff --git a/include/api-test/freelist.hpp b/include/api-test/freelist.hpp deleted file mode 100644 index cbcd56d..0000000 --- a/include/api-test/freelist.hpp +++ /dev/null @@ -1,151 +0,0 @@ -#pragma once -#include -#include - -#include "handle.hpp" - -static constexpr uint32_t default_element_count = 1024U; - -template -class freelist { - public: - - freelist() { - grow(initial_size); - } - - handle add(const T& item) { - // auto id = elements[0U].next_free; - auto id = next_free_id; - - if (id == freelist::invalid_id) { - grow(elements.size()); - - // id = elements[0U].next_free; - id = next_free_id; - } - - auto& element = elements[id]; - - next_free_id = element.next_free; - // elements[0U].next_free = element.next_free; - element.item = std::move(item); - - return { id, ++element.generation }; - } - - void remove(handle handle) { - assert(handle.generation == elements[handle.id].generation); - // elements[handle.id].next_free = elements[0U].next_free; - // elements[0U].next_free = handle.id; - elements[handle.id].next_free = next_free_id; - next_free_id = handle.id; - } - - T& operator[](handle handle) { - assert(handle.generation == elements[handle.id].generation); - return elements[handle.id].item; - } - - const T& operator[](handle handle) const { - assert(handle.generation == elements[handle.id].generation); - return elements[handle.id].item; - } - - static constexpr uint32_t invalid_id = UINT32_MAX; - -private: - void grow(size_t grow_size) { - auto size = elements.size(); - uint32_t next_free = static_cast(size); - next_free_id = next_free; - - elements.reserve(size + grow_size); - - for (auto id { 0U }; id < initial_size; id++) { - elements.push_back( - { - .next_free = static_cast(++next_free % initial_size), - } - ); - } - - elements.back().next_free = freelist::invalid_id; - } - - struct element { - union { - T item; - uint32_t next_free = freelist::invalid_id; - }; - uint32_t generation = 0U; - }; - - std::vector elements; - uint32_t next_free_id; -}; - -template -class idlist { - public: - - idlist() { - grow(initial_size); - } - - handle add() { - // auto id = elements[0U].next_free; - auto id = next_free_id; - - if (id == idlist::invalid_id) { - grow(elements.size()); - - // id = elements[0U].next_free; - id = next_free_id; - } - - auto& element = elements[id]; - next_free_id = element.next_free; - elements[0U].next_free = element.next_free; - element.next_free = idlist::invalid_id; - - return { id, ++element.generation }; - } - - void remove(handle handle) { - assert(handle.generation == elements[handle.id].generation); - // elements[handle.id].next_free = elements[0U].next_free; - // elements[0U].next_free = handle.id; - elements[handle.id].next_free = next_free_id; - next_free_id = handle.id; - } - - static constexpr uint32_t invalid_id = UINT32_MAX; - -private: - void grow(size_t grow_size) { - auto size = elements.size(); - uint32_t next_free = static_cast(size); - next_free_id = next_free; - - elements.reserve(size + grow_size); - - for (auto id { 0U }; id < initial_size; id++) { - elements.push_back( - { - .next_free = static_cast(++next_free% initial_size), - } - ); - } - - elements.back().next_free = idlist::invalid_id; - } - - struct element { - uint32_t next_free = idlist::invalid_id; - uint32_t generation = 0U; - }; - - std::vector elements; - uint32_t next_free_id; -}; diff --git a/include/api-test/handle.hpp b/include/api-test/handle.hpp deleted file mode 100644 index 2c52c01..0000000 --- a/include/api-test/handle.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -// template -// struct handle { -// uint32_t id = handle::invalid_id; -// -// [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } -// -// static constexpr uint32_t invalid_id = -1U; -// }; - -template -struct handle { - uint32_t id = invalid_id; - uint32_t generation = 0U; - - [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } - - static constexpr uint32_t invalid_id = UINT32_MAX; - - // static constexpr handle invalid_handle {}; -}; diff --git a/include/api-test/resource-manager.hpp b/include/api-test/resource-manager.hpp deleted file mode 100644 index f414367..0000000 --- a/include/api-test/resource-manager.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "handle.hpp" -#include "freelist.hpp" -#include "texture.hpp" -#include "buffer.hpp" - -class resourcemanager { -public: - - handle create_texture(const texture_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - const texture& get_texture(handle handle); - - const buffer& get_buffer(handle handle); - -private: - freelist textures; - freelist buffers; -}; diff --git a/include/api-test/texture.hpp b/include/api-test/texture.hpp deleted file mode 100644 index 59bfec1..0000000 --- a/include/api-test/texture.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -struct device_texture; - -class texture { -public: - texture(handle handle); - -private: - handle handle; -}; diff --git a/include/api-test/vk-bindless.hpp b/include/api-test/vk-bindless.hpp deleted file mode 100644 index a5686ff..0000000 --- a/include/api-test/vk-bindless.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include - -#include - -#include "handle.hpp" - -enum BindlessSetType : uint32_t { - GLOBAL, - INSTANCES_UNIFORMS, - DRAWS_UNIFORMS, - MAX, -}; - -enum ConstantType : uint32_t { - GLOBALS, - INSTANCES, - DRAWS, - VERTEX_BUFFER -}; - -enum SamplerType : uint32_t { - NEAREST, - LINEAR, - MAX_SAMPLER, -}; - -struct device_buffer; - -struct bindless_model { -#ifndef USE_VK_DESCRIPTOR_BUFFER - [[nodiscard]] device_buffer& get_draws_uniform_buffer() const; - [[nodiscard]] device_buffer& get_globals_uniform_buffer() const; - - static bindless_model create_bindless_model(); - - static void destroy_bindless_model(bindless_model& bindless); - - VkPipelineLayout graphics_layout; - VkPipelineLayout compute_layout; - VkDescriptorSet sets[BindlessSetType::MAX]; - -private: - static constexpr size_t max_push_constants_size = 128ULL; - -public: - static constexpr size_t max_push_constants_slots_size = 8U; - static constexpr size_t max_push_constants_slots = max_push_constants_size / max_push_constants_slots_size; - -private: - VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; - VkDescriptorPool descriptor_pool; - handle globals_uniform_buffer_handle; - handle instances_uniform_buffer_handle; - handle draws_uniform_buffer_handle; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count = 1024U; - - void create_layout(VkDevice device); - void create_descriptor_pool(VkDevice device); - void allocate_sets(VkDevice device); - - void destroy_descriptor_pool(VkDevice device); - - void create_immutable_samplers(VkDevice device); - - void destroy_immutable_samplers(VkDevice device); - - VkSampler samplers[SamplerType::MAX_SAMPLER]; - - static constexpr size_t globals_uniform_buffer_size = 64ULL * 1024ULL; - static constexpr size_t instances_uniform_buffer_size = 64ULL * 1024ULL; - static constexpr size_t draws_uniform_buffer_size = 64ULL * 1024ULL; -#else - VkPipelineLayout layout; - VkDescriptorSetLayout sets_layout[BindlessSetType::MAX]; - - static constexpr size_t descriptor_pool_allocable_sets_count = 64U; - static constexpr uint32_t set_descriptors_count[BindlessSetType::MAX]{ 1024U }; - - static bindless_model create_bindless_model(VkDevice device); - - static void destroy_bindless_model(VkDevice device, bindless_model& bindless); - - private: - void create_layout(VkDevice device); - - handle storage_image_descriptors; - handle sampled_image_descriptors; -#endif -}; diff --git a/include/api-test/vk-command-buffer.hpp b/include/api-test/vk-command-buffer.hpp deleted file mode 100644 index 08652fd..0000000 --- a/include/api-test/vk-command-buffer.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "handle.hpp" - -#include "vec3.hpp" - -#include "vk-device-types.hpp" - -struct device_texture; -struct device_buffer; -struct device_pipeline; - -struct dispatch_params { - enum class PARAM_BINDING : uint32_t { - PARAM1, - PARAM2, - PARAM3, - PARAM4, - PARAM5, - PARAM6, - PARAM7, - PARAM8, - MAX - }; - - handle pipeline; - vec3u group_size; - vec3u local_group_size; - uint64_t params[static_cast(PARAM_BINDING::MAX)]; -}; - -struct renderpass_params { -private: - struct rect { - int32_t x; - int32_t y; - uint32_t width; - uint32_t height; - }; - -public: - rect render_area; - std::span> color_attachments; -}; - -struct draw_params { - handle pipeline; - handle index_buffer; - uint32_t vertex_count; - uint32_t vertex_offset; - uint32_t instance_count; - uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? - uint64_t instances_address = 0U; - uint64_t uniforms_address = 0U; - uint64_t vertex_address = 0U; -}; - -struct draw_indexed_params { - handle pipeline; - handle index_buffer; - uint32_t vertex_count; - uint32_t vertex_offset; - uint32_t index_offset; - uint32_t instance_count; - uint64_t globals_address = 0U; // TODO: This is probably stupid and should be set elsewhere once ??? - uint64_t instances_address = 0U; - uint64_t uniforms_address = 0U; - uint64_t vertex_address = 0U; -}; - -struct command_buffer { - void start() const; - void stop() const; - - void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; - - void copy(handle buffer_handle, handle texture_handle, uint64_t offset = 0) const; - - VkCommandBuffer vk_command_buffer; - QueueType queue_type; -}; - -// General purpose queue -struct graphics_command_buffer: public command_buffer { - void dispatch(const dispatch_params& params) const; - - void begin_renderpass(const renderpass_params& params) const; - void draw(const draw_params& params) const; - void draw_indexed(const draw_indexed_params& params) const; - void end_renderpass() const; -}; - -struct compute_command_buffer: public command_buffer { - void dispatch(const dispatch_params& params); -}; - -struct transfer_command_buffer: public command_buffer { -}; diff --git a/include/api-test/vk-device-types.hpp b/include/api-test/vk-device-types.hpp deleted file mode 100644 index eddf40c..0000000 --- a/include/api-test/vk-device-types.hpp +++ /dev/null @@ -1,213 +0,0 @@ -#pragma once - -#include - -#include - -#include "freelist.hpp" - -using VmaAllocation = struct VmaAllocation_T*; - -enum class QueueType : uint32_t { - GRAPHICS, - ASYNC_COMPUTE, - TRANSFER, - MAX, -}; - -struct texture_desc { - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - VkImageUsageFlags usages; - VkFormat format; - VkImageType type; - VkImage vk_image = nullptr; - const char* name = nullptr; - - static constexpr auto max_mips = 16U; -}; - -struct device_texture { - void init(const texture_desc& desc); - - void release(); - - void create_views(); - - [[nodiscard]] uint32_t get_storage_index() const { - assert(storage_index.id != handle::invalid_id); - return storage_index.id; - } - - [[nodiscard]] uint32_t get_sampled_index() const { - assert(sampled_index.id != handle::invalid_id); - return sampled_index.id; - } - - VkImage vk_image = nullptr; - VkImageView whole_view = nullptr; - VkImageView mips_views[texture_desc::max_mips] = { nullptr }; - VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkPipelineStageFlags2 stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkAccessFlags2 access = VK_ACCESS_2_NONE; - VkFormat format = VK_FORMAT_UNDEFINED; - VkImageAspectFlags aspects = VK_IMAGE_ASPECT_NONE_KHR; - - uint32_t width = 1U; - uint32_t height = 1U; - uint32_t depth = 1U; - uint32_t mips = 1U; - - private: - handle storage_index; - handle sampled_index; - - VmaAllocation alloc = nullptr; - - static idlist<> storage_indices; - static idlist<> sampled_indices; -}; - - -struct sampler_desc { - VkFilter mag_filter = VK_FILTER_NEAREST; - VkFilter min_filter = VK_FILTER_NEAREST; - VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - VkSamplerAddressMode address_mode_u = VK_SAMPLER_ADDRESS_MODE_REPEAT; - VkSamplerAddressMode address_mode_v = VK_SAMPLER_ADDRESS_MODE_REPEAT; - VkSamplerAddressMode address_mode_w = VK_SAMPLER_ADDRESS_MODE_REPEAT; - float mip_lod_bias = 0.f; - VkBool32 anisotropy = VK_FALSE; - float max_anisotropy = 0.f; - VkBool32 compare_enabled = VK_FALSE; - VkCompareOp compare_op = VK_COMPARE_OP_NEVER; - float min_lod = 0.f; - float max_lod = 0.f; - VkBorderColor border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - VkBool32 unnomalized_coords = VK_FALSE; -}; - -struct device_sampler { - void init(const sampler_desc& desc); - - VkSampler vk_sampler = nullptr; - - [[nodiscard]] uint32_t get_sampler_index() const { - return sampler_index.id; - } - - private: - handle sampler_index; - - static idlist<> sampler_indices; -}; - - -struct buffer_desc { - size_t size; - VkBufferUsageFlags usages; - VkMemoryPropertyFlags memory_properties; - uint32_t memory_usage; -}; - -#define ALIGN(value, alignment) \ - (((value) + ((alignment) - 1)) & ~((alignment) - 1)) - -struct device_buffer { - template - T* allocate() { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - size_t alloc_size = ALIGN(sizeof(T), 16); - if (offset + alloc_size > size) { - reset(); - } - - auto* addr = (T*)(static_cast(mapped_ptr) + offset); - offset += alloc_size; - return addr; - } - - void* allocate(uint64_t alloc_size) { - // size_t alloc_size = (sizeof(T) + 0x100) & 0xffffff00; - alloc_size = ALIGN(alloc_size, 16); - if (offset + alloc_size > size) { - reset(); - } - - auto* addr = (void*)(static_cast(mapped_ptr) + offset); - offset += alloc_size; - return addr; - } - - void reset() { - offset = 0U; - } - - uint64_t offset = 0U; - VkBuffer vk_buffer; - VmaAllocation alloc; - VkDeviceAddress device_address = 0U; - void* mapped_ptr; - size_t size; -}; - -struct graphics_pipeline_desc { - std::span vs_code; - std::span fs_code; - std::span color_attachments_format; - VkFormat depth_attachment_format; - VkFormat stencil_attachment_format; - const char* name; -}; - -struct compute_pipeline_desc { - std::span cs_code; - const char* name; -}; - -struct device_pipeline { - VkPipeline vk_pipeline; - VkPipelineBindPoint bind_point; -}; - -struct semaphore_desc { - VkSemaphoreType type; - uint64_t initial_value = 0U; -}; - -struct device_semaphore { - VkSemaphore vk_semaphore = nullptr; - uint64_t value; -}; - - -typedef struct HWND__* HWND; - -struct surface_desc { - HWND window_handle; - VkSurfaceFormatKHR surface_format; - VkPresentModeKHR present_mode; - VkImageUsageFlags usages; - uint32_t image_count = surface_desc::default_image_count; - - static constexpr uint32_t max_image_count = 3U; - static constexpr uint32_t default_image_count = 3U; -}; - -struct device_surface { - VkSurfaceKHR vk_surface; - VkSwapchainKHR vk_swapchain; - VkSurfaceFormatKHR surface_format; - - handle swapchain_images[surface_desc::max_image_count]; - uint32_t image_index; - uint32_t image_count; - uint32_t frame_index = 0U; - - handle acquire_semaphores[surface_desc::max_image_count]; - handle submit_semaphores[surface_desc::max_image_count]; - - uint32_t acquire_image_index(); -}; diff --git a/include/api-test/vk-device.hpp b/include/api-test/vk-device.hpp deleted file mode 100644 index 1b04bb3..0000000 --- a/include/api-test/vk-device.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include "freelist.hpp" -#include "vk-device-types.hpp" -#include "vk-bindless.hpp" - -using VmaAllocator = struct VmaAllocator_T*; - -struct command_buffer; -class window; - -class vkdevice { - struct queue { - VkQueue vk_queue; - uint32_t index; - VkQueueFlags usages; - VkCommandPool command_pool; - }; - - public: - void init(); - void deinit(); - - static inline vkdevice& get_render_device() { - return render_device; - } - - handle create_texture(const texture_desc& desc); - - handle create_sampler(const sampler_desc& desc); - - handle create_buffer(const buffer_desc& desc); - - handle create_graphics_pipeline(const graphics_pipeline_desc& desc); - - handle create_compute_pipeline(const compute_pipeline_desc& desc); - - handle create_surface(const surface_desc& desc); - - handle create_semaphore(const semaphore_desc& desc, const char* name); - - void destroy_texture(handle handle); - - void destroy_sampler(handle handle); - - void destroy_buffer(handle handle); - - void destroy_pipeline(handle handle); - - void destroy_semaphore(handle handle); - - void destroy_surface(handle handle); - - template - void allocate_command_buffers(buffer_type* buffers, size_t count, QueueType queue_type, const char* name) { - allocate_command_buffers(static_cast(buffers), count, queue_type, name); - } - - [[nodiscard]] inline device_texture& get_texture(handle handle) { - return textures[handle]; - } - - [[nodiscard]] inline device_sampler& get_sampler(handle handle) { - return samplers[handle]; - } - - [[nodiscard]] inline device_buffer& get_buffer(handle handle) { - return buffers[handle]; - } - - [[nodiscard]] inline const device_pipeline& get_pipeline(handle handle) const { - return pipelines[handle]; - } - - [[nodiscard]] inline device_surface& get_surface(handle handle) { - return surfaces[handle]; - } - - [[nodiscard]] inline device_semaphore& get_semaphore(handle handle) { - return semaphores[handle]; - } - - [[nodiscard]] inline const bindless_model& get_bindingmodel() const { - return bindless; - } - - inline VkDevice get_device() { - return device; - } - - inline VmaAllocator get_allocator() { - return gpu_allocator; - } - - // uint64_t submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle); - uint32_t acquire_image_index(handle surface_handle); - uint64_t submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count); - uint64_t submit(command_buffer* buffers, uint32_t count); - - void present(handle surface_handle); - - void wait(); - - private: - vkdevice() = default; - ~vkdevice() = default; - - void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name); - - VkShaderModule create_shader_module(const std::span& shader_code); - - void create_swapchain(const surface_desc& desc, device_surface& surface); - - // TODO: Wrap in a struct called adapter ? - void create_instance(); - - void create_device(); - - void create_memory_allocator(); - - void create_command_pools(); - - void pick_physical_device(); - - static bool device_support_features(VkPhysicalDevice physical_dev); - - void create_debug_layer_callback(); - - queue queues[static_cast(QueueType::MAX)]; - - VkInstance instance; - VkPhysicalDevice physical_device; - VkDevice device; - - VmaAllocator gpu_allocator; - - bindless_model bindless; - - static constexpr size_t max_allocable_command_buffers = 16; - static constexpr size_t max_submitable_command_buffers = 16; - - freelist textures; - freelist samplers; - freelist buffers; - freelist pipelines; - freelist surfaces; - freelist semaphores; - - device_semaphore timeline_semaphore; - - static vkdevice render_device; - -#ifdef _DEBUG - VkDebugUtilsMessengerEXT debug_messenger; -#endif // _DEBUG -}; diff --git a/include/api-test/vk-utils.hpp b/include/api-test/vk-utils.hpp deleted file mode 100644 index 205e103..0000000 --- a/include/api-test/vk-utils.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include - -#ifdef _DEBUG -#define VKCHECK(result) assert((result) == VK_SUCCESS) -#else -#define VKCHECK(result) result -#endif - -VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* data, - void*); diff --git a/include/buffer.hpp b/include/buffer.hpp new file mode 100644 index 0000000..64c4881 --- /dev/null +++ b/include/buffer.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +#include "handle.hpp" + +struct device_buffer; + +class buffer { +public: + buffer(handle handle); + +private: + handle handle; + +}; diff --git a/include/bvh-node.hpp b/include/bvh-node.hpp deleted file mode 100644 index 525e1c8..0000000 --- a/include/bvh-node.hpp +++ /dev/null @@ -1,320 +0,0 @@ -#ifndef __BVH_NODE_HPP_ -#define __BVH_NODE_HPP_ - -#include -#include -#include - -#include "aabb.hpp" -// #include "sphere.hpp" -#include "triangle.hpp" - -struct bvh_node { - aabb bounding_box; - - int32_t next_id = -1; - int32_t primitive_id = -1; - uint32_t padding[2]; -}; - -struct packed_bvh_node { - float min[3]; - int32_t next_id = -1; - float max[3]; - int32_t primitive_id = -1; -}; - -struct temp_node : public bvh_node { - int32_t left_id; - int32_t df_id; -}; - -class bvh { -public: - // bvh(std::vector& spheres, std::vector& packed_nodes) - // :spheres(spheres) { - // packed_nodes.resize(2 * spheres.size() - 1); - // temp_nodes = std::vector(2 * spheres.size() - 1); - // leafs = std::vector(spheres.size()); - - // for (uint32_t id = 0; id < spheres.size(); id++) { - // leafs[id].bounding_box = aabb(spheres[id].center, spheres[id].radius); - // leafs[id].primitive_id = id; - // } - - // temp_nodes[0] = temp_node(); - - // temp_nodes[0].bounding_box = compute_bounds(0, spheres.size()); - // subdivide(0, 0, spheres.size()); - - // set_depth_first_order(); - - // for (uint32_t id = 0; id < temp_nodes.size(); id++) { - // auto old_node = temp_nodes[id]; - // auto &node = packed_nodes[old_node.df_id]; - - // node.primitive_id = old_node.primitive_id; - - // node.min[0] = old_node.bounding_box.minimum.v[0]; - // node.min[1] = old_node.bounding_box.minimum.v[1]; - // node.min[2] = old_node.bounding_box.minimum.v[2]; - - // node.max[0] = old_node.bounding_box.maximum.v[0]; - // node.max[1] = old_node.bounding_box.maximum.v[1]; - // node.max[2] = old_node.bounding_box.maximum.v[2]; - - // if (old_node.next_id != -1) { - // node.next_id = temp_nodes[old_node.next_id].df_id; - // } - // } - - // // exporter(); - // } - - bvh(std::vector& triangles, std::vector& packed_nodes) - :triangles(triangles) { - packed_nodes.resize(2 * triangles.size() - 1); - temp_nodes = std::vector(2 * triangles.size() - 1); - leafs = std::vector(triangles.size()); - - for (uint32_t id = 0; id < triangles.size(); id++) { - leafs[id].bounding_box = aabb(triangles[id]); - leafs[id].primitive_id = id; - } - - temp_nodes[0] = temp_node(); - - temp_nodes[0].bounding_box = compute_bounds(0, triangles.size()); - subdivide(0, 0, triangles.size()); - - set_depth_first_order(); - - for (uint32_t id = 0; id < temp_nodes.size(); id++) { - auto old_node = temp_nodes[id]; - auto &node = packed_nodes[old_node.df_id]; - - node.primitive_id = old_node.primitive_id; - - node.min[0] = old_node.bounding_box.minimum.v[0]; - node.min[1] = old_node.bounding_box.minimum.v[1]; - node.min[2] = old_node.bounding_box.minimum.v[2]; - - node.max[0] = old_node.bounding_box.maximum.v[0]; - node.max[1] = old_node.bounding_box.maximum.v[1]; - node.max[2] = old_node.bounding_box.maximum.v[2]; - - if (old_node.next_id != -1) { - node.next_id = temp_nodes[old_node.next_id].df_id; - } - } - - // exporter(); - } - - //------------------------- - // BVH exporter for graphviz - //------------------------- - void exporter() { - std::cout << "digraph bvh {" << std::endl; - - traverse_depth_first(temp_nodes, 0); - - // traverse_depth_first_ordered(-1, 0); - - std::cout << "}" << std::endl; - } - - bool traverse_depth_first(std::vector& nodes, int32_t id) { - if (id <= 0) { - std::cout << ";" << std::endl; - return false; - } - - std::cout << " -> " << id; - if (traverse_depth_first(nodes, nodes[id].left_id)) { - std::cout << "\t " << id; - traverse_depth_first(nodes, nodes[id].left_id + 1); - } - - return true; - } - - int32_t traverse_depth_first_ordered(std::vector& nodes, int32_t parent_id, int32_t id) { - if (id == -1) { - return -1; - } - - if (nodes[id].primitive_id == -1) { - int32_t left = id + 1; - int32_t next_id; - - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - next_id = traverse_depth_first_ordered(nodes, id, left); - - if (next_id != -1) { - return traverse_depth_first_ordered(nodes, id, next_id); - } - } else if (nodes[id].primitive_id != -1 && nodes[id].next_id != -1) { - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - return nodes[id].next_id; - } else { - std::cout << "\t " << parent_id << " -> " << id << ";\n"; - } - - return -1; - } - - std::vector temp_nodes; - std::vector leafs; - - // std::vector& spheres; - std::vector& triangles; - - uint32_t next_node_id = 0; - -private: - - static constexpr uint32_t buckets_count = 12; - - aabb compute_bounds(uint32_t begin, uint32_t end) { - aabb global_box = aabb(); - - for (uint32_t id = begin; id < end; id++) { - global_box.union_with(leafs[id].bounding_box); - } - - return global_box; - } - - void subdivide(uint32_t parent_id, uint32_t begin, uint32_t end) { - size_t count = end - begin; - if (count == 1) { - temp_nodes[parent_id] = leafs[begin]; - return; - } - - auto left_id = ++next_node_id; - auto right_id = ++next_node_id; - - temp_nodes[parent_id].left_id = left_id; - - if (count == 2) { - temp_nodes[left_id] = leafs[begin]; - temp_nodes[right_id] = leafs[begin + 1]; - } else { - auto parent_bb = temp_nodes[parent_id].bounding_box; - int32_t split_axis = parent_bb.maximum_axis(); - - if (count <= 4) { - // Subdivide the node by splitting the set in two equal parts - std::sort(leafs.begin() + begin, leafs.begin() + end, - // [&](const bvh_node& a, const bvh_node& b) { - // return spheres[a.primitive_id].center[split_axis] < spheres[b.primitive_id].center[split_axis]; - // } - [&](const bvh_node& a, const bvh_node& b) { - return triangles[a.primitive_id].center()[split_axis] < triangles[b.primitive_id].center()[split_axis]; - } - ); - - temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + (count / 2)); - temp_nodes[right_id].bounding_box = compute_bounds(begin + (count / 2), end); - - subdivide(left_id, begin, begin + (count / 2)); - subdivide(right_id, begin + (count / 2), end); - } else { - // Subdivide based on SAH - struct Bucket { - uint32_t count = 0; - aabb bb; - }; - Bucket buckets[buckets_count]; - - // Split the set in N spatial buckets - // Simplify the optimal split axis search to just an axis between each bucket - aabb centroid_bounds; - - for (size_t i = begin; i < end; i++) { - auto primitive = triangles[leafs[i].primitive_id]; - centroid_bounds.union_with(primitive.center()); - // auto primitive = spheres[leafs[i].primitive_id]; - // centroid_bounds.union_with(primitive.center); - } - - float split_axis_size = centroid_bounds.maximum[split_axis] - centroid_bounds.minimum[split_axis]; - for (size_t i = begin; i < end; i++) { - auto primitive = triangles[leafs[i].primitive_id]; - auto normalized_offset = (primitive.center()[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size; - // auto primitive = spheres[leafs[i].primitive_id]; - // auto normalized_offset = (primitive.center[split_axis] - centroid_bounds.minimum[split_axis]) / split_axis_size; - uint32_t bucket_index = normalized_offset * buckets_count; - if (bucket_index == buckets_count) { - bucket_index -= 1; - } - - buckets[bucket_index].count++; - buckets[bucket_index].bb.union_with(leafs[i].bounding_box); - } - - // Compute each potential split axis cost - float buckets_cost[buckets_count - 1] = { 0.f }; - for (size_t bucket_index = 0; bucket_index < buckets_count - 1; bucket_index++) { - aabb right_side_bb, left_side_bb; - float right_side_count = 0, left_side_count = 0; - - for (size_t i = 0; i <= bucket_index; i++) { - left_side_bb.union_with(buckets[i].bb); - left_side_count += buckets[i].count; - } - - for (size_t i = bucket_index + 1; i < buckets_count; i++) { - right_side_bb.union_with(buckets[i].bb); - right_side_count += buckets[i].count; - } - - float left = left_side_count * left_side_bb.surface_area(); - float right = right_side_count * right_side_bb.surface_area(); - buckets_cost[bucket_index] = 0.125f + (left + right) / parent_bb.surface_area(); - } - - float min_cost = buckets_cost[0]; - uint32_t min_cost_bucket = 0; - for (size_t bucket_index = 1; bucket_index < buckets_count - 1; bucket_index++) { - if (buckets_cost[bucket_index] < min_cost) { - min_cost = buckets_cost[bucket_index]; - min_cost_bucket = bucket_index; - } - } - - uint32_t middle_primitive_index = buckets[0].count; - for (size_t bucket_index = 1; bucket_index <= min_cost_bucket; bucket_index++) { - middle_primitive_index += buckets[bucket_index].count; - } - - temp_nodes[left_id].bounding_box = compute_bounds(begin, begin + middle_primitive_index); - temp_nodes[right_id].bounding_box = compute_bounds(begin + middle_primitive_index, end); - - subdivide(left_id, begin, begin + middle_primitive_index); - subdivide(right_id, begin + middle_primitive_index, end); - } - } - } - - void set_depth_first_order() { - int32_t df_index = 0; - depth_first_order(0, -1, df_index); - } - - - void depth_first_order(int32_t id, int32_t next_id, int32_t &new_id) { - auto &node = temp_nodes[id]; - node.next_id = next_id; - node.df_id = new_id++; - - if (node.left_id > 0) { - depth_first_order(node.left_id, node.left_id + 1, new_id); - depth_first_order(node.left_id + 1, next_id, new_id); - } - } -}; - -#endif // !__BVH_NODE_HPP_ diff --git a/include/compute-renderpass.hpp b/include/compute-renderpass.hpp deleted file mode 100644 index 6799171..0000000 --- a/include/compute-renderpass.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include "renderpass.hpp" -#include "vk-api.hpp" - -class Texture; -class Buffer; - -class ComputeRenderpass : public Renderpass { - public: - - ComputeRenderpass(vkapi& api); - ~ComputeRenderpass() override; - - void set_pipeline(const char* shader_name); - - void set_dispatch_size(size_t count_x, size_t count_y, size_t count_z); - - void set_ouput_texture(Texture* out_texture); - - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - - // TODO: Do not use vulkan api type - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - Texture* output_texture; - - private: - - std::vector input_textures; - - uint8_t constants[64]; - - size_t group_count_x; - size_t group_count_y; - size_t group_count_z; - - pipeline pipeline; -}; diff --git a/include/dx12-command-buffer.hpp b/include/dx12-command-buffer.hpp new file mode 100644 index 0000000..e9de39a --- /dev/null +++ b/include/dx12-command-buffer.hpp @@ -0,0 +1,28 @@ +#include + +#include "handle.hpp" +#include "dx12-device-types.hpp" + +namespace dx12 { + struct command_buffer { + void start() const; + void stop() const; + + // void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; + + void copy(handle src_buffer, handle dst_texture, uint64_t offset = 0) const; + + ID3D12CommandAllocator* command_allocator; + ID3D12GraphicsCommandList* dx12_command_buffer; + dx12::QueueType queue_type; + }; + + struct graphics_command_buffer: public command_buffer { + // void dispatch(const dispatch_params& params) const; + + // void begin_renderpass(const renderpass_params& params) const; + // void draw(const draw_params& params) const; + // void draw_indexed(const draw_indexed_params& params) const; + // void end_renderpass() const; + }; +} diff --git a/include/dx12-device-types.hpp b/include/dx12-device-types.hpp new file mode 100644 index 0000000..4b2fc42 --- /dev/null +++ b/include/dx12-device-types.hpp @@ -0,0 +1,74 @@ +#pragma once +#include +#include +#include + +#include + +namespace dx12 { + enum class QueueType : uint32_t { + GRAPHICS, + ASYNC_COMPUTE, + TRANSFER, + MAX, + }; + + struct buffer_desc { + uint32_t size; + bool map; + + D3D12_RESOURCE_STATES states; + D3D12_RESOURCE_FLAGS usages; + D3D12_HEAP_TYPE heap_type = D3D12_HEAP_TYPE_DEFAULT; + }; + + struct device_buffer { + ID3D12Resource* resource; + + D3D12MA::Allocation* alloc; + uint32_t size; + void* mapped_ptr = nullptr; + }; + + + struct texture_desc { + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + + D3D12_RESOURCE_STATES states; + D3D12_RESOURCE_FLAGS usages; + DXGI_FORMAT format; + D3D12_RESOURCE_DIMENSION type; + }; + + struct device_texture { + ID3D12Resource* resource; + D3D12MA::Allocation* alloc; + + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + uint64_t row_pitch = 1U; + + DXGI_FORMAT format; + + }; + + struct surface_desc { + HWND window_handle; + DXGI_FORMAT surface_format; + DXGI_SWAP_EFFECT present_mode; + DXGI_USAGE usages; + uint32_t image_count = surface_desc::default_image_count; + + static constexpr uint32_t max_image_count = 3U; + static constexpr uint32_t default_image_count = 3U; + }; + + struct device_surface { + IDXGISwapChain1* swapchain; + }; +} diff --git a/include/dx12-device.hpp b/include/dx12-device.hpp new file mode 100644 index 0000000..baa5b60 --- /dev/null +++ b/include/dx12-device.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include +#include + +#include "freelist.hpp" +#include "dx12-device-types.hpp" + +#include "D3D12MemAlloc.h" + +namespace dx12 { + struct command_buffer; + + class device { + struct queue { + ID3D12CommandQueue* dx_queue; + D3D12_COMMAND_LIST_TYPE type; + }; + public: + void init(); + + static inline device& get_render_device() { + return render_device; + } + + handle create_surface(const surface_desc& desc); + + handle create_buffer(const buffer_desc& desc); + + handle create_texture(const texture_desc& desc); + + void create_graphics_pipeline() {}; + + void create_compute_pipeline() {}; + + void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type); + + + [[nodiscard]] inline device_surface& get_surface(handle handle) { + return surfaces[handle]; + } + + [[nodiscard]] inline device_buffer& get_buffer(handle handle) { + return buffers[handle]; + } + + [[nodiscard]] inline device_texture& get_texture(handle handle) { + return textures[handle]; + } + + [[nodiscard]] inline ID3D12Device* get_device() const { + return device; + } + + uint32_t submit(command_buffer* buffers, uint32_t count); + + void wait(); + + private: + IDXGIFactory3* factory; + IDXGIAdapter* adapter; + ID3D12Debug* debug_interface; + + D3D12MA::Allocator* allocator; + + ID3D12Device* device; + ID3D12Fence* fence; + uint64_t fence_value = 0U; + queue queues[static_cast(QueueType::MAX)]; + + freelist surfaces; + freelist buffers; + freelist textures; + + static constexpr size_t max_allocable_command_buffers = 16U; + static constexpr size_t max_submitable_command_buffers = 16U; + + static class device render_device; + + struct bindless_model { + void init(); + + [[nodiscard]] inline ID3D12DescriptorHeap* const* get_heaps() const { + return &resources_heap; + } + + ID3D12DescriptorHeap* resources_heap; + ID3D12DescriptorHeap* samplers_heap; + } model; + + public: + [[nodiscard]] static inline const device::bindless_model& get_bindless_model() { + return render_device.model; + } + }; + +} diff --git a/include/freelist.hpp b/include/freelist.hpp new file mode 100644 index 0000000..2df1ca5 --- /dev/null +++ b/include/freelist.hpp @@ -0,0 +1,158 @@ +#pragma once + +#include "utils.hpp" +#include "handle.hpp" + +static constexpr u32 default_element_count = 1024U; + +template +class freelist { + public: + + freelist() { + grow(initial_size); + } + + handle add(const T& item) { + // auto id = elements[0U].next_free; + auto id = next_free_id; + + if (id == freelist::invalid_id) { + grow(elements.size()); + + // id = elements[0U].next_free; + id = next_free_id; + } + + auto& element = elements[id]; + + next_free_id = element.next_free; + // elements[0U].next_free = element.next_free; + element.item = std::move(item); + + assert(element.generation + 1 != UINT32_MAX); + + return { id, ++element.generation }; + } + + void remove(handle handle) { + assert(handle.generation == elements[handle.id].generation); + // elements[handle.id].next_free = elements[0U].next_free; + // elements[0U].next_free = handle.id; + elements[handle.id].next_free = next_free_id; + next_free_id = handle.id; + } + + T& operator[](handle handle) { + assert(handle.generation == elements[handle.id].generation); + return elements[handle.id].item; + } + + const T& operator[](handle handle) const { + assert(handle.generation == elements[handle.id].generation); + return elements[handle.id].item; + } + + static constexpr uint32_t invalid_id = UINT32_MAX; + + struct element { + union { + T item; + uint32_t next_free = freelist::invalid_id; + }; + uint32_t generation = 0U; + }; + + const std::vector& get_list() const { + return elements; + } + +private: + void grow(size_t grow_size) { + size_t size = elements.size(); + uint32_t next_free = static_cast(size); + next_free_id = next_free; + + elements.reserve(size + grow_size); + + for (auto id { 0U }; id < initial_size; id++) { + elements.push_back( + { + .next_free = static_cast(++next_free % initial_size), + } + ); + } + + // this makes it impossible to know + elements.back().next_free = freelist::invalid_id; + elements.back().next_free = freelist::invalid_id; + } + + std::vector elements; + uint32_t next_free_id; +}; + +template +class idlist { + public: + + idlist() { + grow(initial_size); + } + + handle add() { + // auto id = elements[0U].next_free; + auto id = next_free_id; + + if (id == idlist::invalid_id) { + grow(elements.size()); + + // id = elements[0U].next_free; + id = next_free_id; + } + + auto& element = elements[id]; + next_free_id = element.next_free; + elements[0U].next_free = element.next_free; + element.next_free = idlist::invalid_id; + + return { id, ++element.generation }; + } + + void remove(handle handle) { + assert(handle.generation == elements[handle.id].generation); + // elements[handle.id].next_free = elements[0U].next_free; + // elements[0U].next_free = handle.id; + elements[handle.id].next_free = next_free_id; + next_free_id = handle.id; + } + + static constexpr uint32_t invalid_id = UINT32_MAX; + +private: + void grow(size_t grow_size) { + auto size = elements.size(); + uint32_t next_free = static_cast(size); + next_free_id = next_free; + + elements.reserve(size + grow_size); + + for (auto id { 0U }; id < initial_size; id++) { + elements.push_back( + { + .next_free = static_cast(++next_free% initial_size), + } + ); + } + + elements.back().next_free = idlist::invalid_id; + } + + struct element { + uint32_t next_free = idlist::invalid_id; + uint32_t generation = 0U; + }; + + std::vector elements; + uint32_t next_free_id; +}; diff --git a/include/handle.hpp b/include/handle.hpp new file mode 100644 index 0000000..484b217 --- /dev/null +++ b/include/handle.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +template +struct handle { + uint32_t id = invalid_id; + uint32_t generation = 0U; + + [[nodiscard]] inline bool is_valid() const { return id != handle::invalid_id; } + + static constexpr uint32_t invalid_id = UINT32_MAX; +}; diff --git a/include/primitive-renderpass.hpp b/include/primitive-renderpass.hpp deleted file mode 100644 index 95562fe..0000000 --- a/include/primitive-renderpass.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#pragma once - -#include - -#include "renderpass.hpp" -#include "vk-renderer.hpp" - -class Buffer; -class Texture; -class Sampler; -class Primitive; - -class PrimitiveRenderpass : public Renderpass { - public: - - PrimitiveRenderpass(vkapi& api); - - void add_primitive(Primitive* new_primitive); - - void add_color_attachment(VkFormat format); - - void set_depth_stencil(Texture* depth_stencil); - - void set_viewport(float x, float y, float width, float height); - - void set_color_attachment(uint32_t index, Texture* attachment); - - void finalize_render_pass(); - - void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) final; - - VkRenderPass render_pass = VK_NULL_HANDLE; - - private: - - void create_framebuffers(); - - void recreate_framebuffers(); - - VkViewport viewport = { .minDepth = 0.f, .maxDepth = 1.f }; - - std::vector color_attachments; - std::vector color_attachments_view; - std::vector color_attachments_format; - - framebuffer framebuffers[vkrenderer::virtual_frames_count]; - - std::vector primitives; -}; - - -class Primitive { - public: - - Primitive(PrimitiveRenderpass& render_pass); - - void set_pipeline(const char* shader_name); - - void set_constant_offset(off_t offset); - void set_constant(off_t offset, uint64_t* constant); - void set_constant(off_t offset, Texture* texture); - void set_constant(off_t offset, Buffer* buffer); - void set_constant(off_t offset, Sampler* sampler); - - void set_index_buffer(Buffer* buffer); - - void set_scissor(int32_t x, int32_t y, uint32_t width, uint32_t height); - - void set_draw_info(size_t vertex_count, off_t indices_off, off_t vertex_off); - - void render(VkCommandBuffer command_buffer); - - -private: - - vkapi& api; - - PrimitiveRenderpass& primitive_render_pass; - - pipeline pipeline; - - Buffer* index_buffer; - - size_t element_count; - off_t indices_offset; - off_t vertex_offset; - - off_t constant_offset; - - VkRect2D scissor = {}; - - uint8_t constants[64]; -}; diff --git a/include/renderpass.hpp b/include/renderpass.hpp deleted file mode 100644 index da116dd..0000000 --- a/include/renderpass.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -using VkCommandBuffer = struct VkCommandBuffer_T*; - -class vkrenderer; -class vkapi; - -class Renderpass { - public: - - Renderpass(vkapi& api) - :api(api) - {}; - - virtual ~Renderpass() = default; - - // TODO: Do not use vulkan api type - virtual void execute(vkrenderer& renderer, VkCommandBuffer command_buffer) = 0; - - protected: - vkapi &api; -}; diff --git a/include/texture.hpp b/include/texture.hpp index aac7b69..59bfec1 100644 --- a/include/texture.hpp +++ b/include/texture.hpp @@ -1,83 +1,17 @@ -#include - -using VkImage = struct VkImage_T*; - -struct TextureDesc { - VkImageType type; - VkFormat format; - VkExtent size; - VkImageUsageFlags usages; -}; - -class Texture { - public: - Texture(const TextureDesc desc) - : description(desc) { - create_device_image(); - } - - // Texture(handle image_handle) { - // const auto& image = vkrenderer::api.get_image(image_handle); - // width = image.size.width; - // height = image.size.height; - // depth = image.size.depth; - - // device_image = image_handle; - // } - - // Texture(size_t width, size_t height, size_t depth, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM, Sampler* texture_sampler = nullptr) - // : width(width), height(height), depth(depth) { - // sampler = texture_sampler; - // device_image = vkrenderer::api.create_image( - // { .width = (uint32_t)width, .height = (uint32_t)height, .depth = 1 }, - // format, - // VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); - // } +#pragma once - void update(void* new_data) { - if (data == nullptr) { - free(data); - } - data = new_data; - - vkrenderer::queue_image_update(this); - } - - ~Texture() { - vkrenderer::api.destroy_image(device_image); - - if (data == nullptr) { - free(data); - } - } - - [[nodiscard]] size_t size() const { - const auto& image = vkrenderer::api.get_image(device_image); - return width * height * depth * pixel_size(image.format); - } - - static size_t pixel_size(VkFormat format) { - switch (format) { - case VK_FORMAT_R8G8B8A8_UNORM: - return 4; - default: - return 0; - } - } - - // Sampler* sampler = nullptr; +#include - private: - void create_device_image(); +#include - void* data = nullptr; +#include "handle.hpp" - size_t width = 0; - size_t height = 0; - size_t depth = 0; +struct device_texture; - TextureDesc description; +class texture { +public: + texture(handle handle); - VmaAllocationInfo alloc_info; - VkImage device_image; +private: + handle handle; }; diff --git a/include/vk-api.hpp b/include/vk-api.hpp deleted file mode 100644 index a3442f1..0000000 --- a/include/vk-api.hpp +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef __VK_API_HPP_ -#define __VK_API_HPP_ - -#include -#include - -#include - -using VmaAllocation = struct VmaAllocation_T*; - -struct buffer { - VmaAllocation alloc; - void* device_ptr; - VkBuffer handle; - size_t size; - VkDeviceAddress device_address; -}; - -struct pipeline { - std::vector shader_modules; - VkPipeline handle = VK_NULL_HANDLE; - VkPipelineBindPoint bind_point; -}; - -using bindless_index = uint32_t; -using handle = uint32_t; - -struct image { - VkImage handle; - VkImageView view; - VmaAllocation alloc; - VkImageSubresourceRange subresource_range; - VkFormat format; - VkExtent3D size; - VkImageUsageFlags usages; - bindless_index bindless_storage_index = 0; - bindless_index bindless_sampled_index = 0; - - VkImageLayout previous_layout = VK_IMAGE_LAYOUT_UNDEFINED; - VkPipelineStageFlags previous_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - VkAccessFlags previous_access = 0; -}; - -struct swapchain { - uint32_t image_count; - std::vector images; - VkSwapchainKHR handle; - VkSurfaceFormatKHR surface_format; - VkExtent2D extent; -}; - -struct framebuffer { - VkFramebuffer handle; - VkExtent2D size; -}; - -struct sampler { - VkSampler handle; - bindless_index bindless_index; -}; - -struct global_descriptor { - VkDescriptorSetLayout set_layout; - VkPipelineLayout pipeline_layout; - VkDescriptorSet set; - - std::vector index_pool[3]; - - static constexpr uint32_t pool_size = 1024U; - - global_descriptor() { - for (int32_t index = pool_size; index > 0; index--) { - index_pool[0].push_back((uint32_t)index); - index_pool[1].push_back((uint32_t)index); - index_pool[2].push_back((uint32_t)index); - } - } - - uint32_t allocate(VkDescriptorType type) { - auto& pool = index_pool[descriptor_type_binding(type)]; - auto index = pool.back(); - pool.pop_back(); - - return index; - } - - void free(uint32_t index, VkDescriptorType type) { - assert(index != 0); - index_pool[descriptor_type_binding(type)].push_back(index); - } - - static int32_t descriptor_type_binding(VkDescriptorType type) { - switch (type) { - case VK_DESCRIPTOR_TYPE_SAMPLER: - return 0; - case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - return 1; - case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: - return 2; - default: - assert(true && "descriptor type not supported"); - return -1; - } - } -}; - -class window; -class vkcontext; - -class vkapi { - public: - vkapi(vkcontext& context); - ~vkapi(); - - handle create_buffer(size_t data_size, VkBufferUsageFlags buffer_usage, uint32_t mem_usage); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size); - void copy_buffer(VkCommandBuffer cmd_buf, handle src, handle dst, size_t size, size_t buffer_offset = 0); - void destroy_buffer(handle buffer); - - - handle create_image(VkExtent3D size, VkFormat format, VkImageUsageFlags usages); - void destroy_image(handle image); - std::vector create_images(VkExtent3D size, VkFormat format, VkImageUsageFlags usages, size_t image_count); - void destroy_images(std::vector& imgs); - - - [[nodiscard]] VkFence create_fence() const; - void destroy_fence(VkFence fence) const; - [[nodiscard]] std::vector create_fences(size_t fences_count) const; - void destroy_fences(VkFence fences[], size_t fences_count) const; - - - [[nodiscard]] VkSemaphore create_semaphore() const; - void destroy_semaphore(VkSemaphore semaphore) const; - [[nodiscard]] std::vector create_semaphores(size_t semaphores_count) const; - void destroy_semaphores(VkSemaphore semaphores[], size_t semaphores_count) const; - - handle create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - void destroy_sampler(handle sampler); - - - [[nodiscard]] VkCommandPool create_command_pool() const; - - void allocate_command_buffers(VkCommandPool command_pool, VkCommandBuffer* command_buffers, size_t count) const; - - - VkRenderPass create_render_pass(std::vector& color_attachments_format, VkImageLayout initial_layout, VkImageLayout final_layout); - VkRenderPass create_render_pass(std::vector& color_attachments_format, VkFormat depth_attachement_format); - void destroy_render_pass(VkRenderPass render_pass); - - - framebuffer create_framebuffer(VkRenderPass render_pass, std::vector& formats, VkExtent2D size); - std::vector create_framebuffers(VkRenderPass render_pass, std::vector& formats, VkExtent2D size, uint32_t framebuffer_count); - void destroy_framebuffer(framebuffer framebuffer) const; - void destroy_framebuffers(std::vector& framebuffers) const; - - - pipeline create_compute_pipeline(const char* shader_name) const; - pipeline create_graphics_pipeline(const char* shader_name, VkShaderStageFlagBits shader_stages, VkRenderPass render_pass, std::vector& dynamic_states) const; - void destroy_pipeline(pipeline& pipeline) const; - - - VkSurfaceKHR create_surface(window& wnd) const; - void destroy_surface(VkSurfaceKHR surface); - - - swapchain create_swapchain(VkSurfaceKHR surface, size_t min_image_count, VkImageUsageFlags usages, VkSwapchainKHR old_swapchain); - void destroy_swapchain(swapchain& swapchain); - - void update_descriptor_image(handle img, VkDescriptorType type); - void update_descriptor_images(std::vector& images, VkDescriptorType type); - void update_descriptor_sampler(handle sampler); - void update_descriptor_samplers(std::vector& samplers); - - - void update_constants(VkCommandBuffer command_buffer, VkShaderStageFlagBits shader_stage, off_t offset, size_t size, void* data); - - void start_record(VkCommandBuffer command_buffer); - - void image_barrier(VkCommandBuffer command_buffer, VkImageLayout dst_layout, VkPipelineStageFlagBits dst_stage, VkAccessFlags dst_access, handle image); - - void begin_render_pass(VkCommandBuffer command_buffer, VkRenderPass render_pass, std::vector& attachments, framebuffer framebuffer, VkExtent2D size); - void end_render_pass(VkCommandBuffer command_buffer); - - void run_compute_pipeline(VkCommandBuffer command_buffer, pipeline& pipeline, size_t group_count_x, size_t group_count_y, size_t group_count_z); - - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, uint32_t vertex_count, uint32_t vertex_offset); - void draw(VkCommandBuffer command_buffer, pipeline& pipeline, handle index_buffer, uint32_t primitive_count, uint32_t indices_offset, uint32_t vertices_offset); - - void blit_full(VkCommandBuffer command_buffer, handle src_image, handle dst_image); - - void end_record(VkCommandBuffer command_buffer); - - VkResult submit(VkCommandBuffer command_buffers[], size_t command_buffers_count, VkSemaphore wait_semaphore, VkSemaphore signal_semaphore, VkFence submission_fence) const; - - VkResult present(swapchain& swapchain, uint32_t image_index, VkSemaphore wait_semaphore) const; - - const buffer& get_buffer(handle buffer_handle) { return *buffers[buffer_handle]; }; - - const image& get_image(handle image_handle) { return *images[image_handle]; }; - - const sampler& get_sampler(handle sampler_handle) { return *samplers[sampler_handle]; }; - - vkcontext& context; - - private: - global_descriptor bindless_descriptor; - - static const char* shader_stage_extension(VkShaderStageFlags shader_stage); - - // TODO: Use freelists instead - std::vector buffers; - std::vector images; - std::vector samplers; - - VkDescriptorPool descriptor_pool; -}; - -#endif // !__VK_API_HPP_ diff --git a/include/vk-bindless.hpp b/include/vk-bindless.hpp new file mode 100644 index 0000000..008e420 --- /dev/null +++ b/include/vk-bindless.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include "handle.hpp" + +enum UniformTypes : uint32_t { + GLOBAL, + PASS, + DRAW, + MAX, +}; + +enum SamplerType : uint32_t { + NEAREST, + LINEAR, + MAX_SAMPLER, +}; + +struct device_buffer; + +struct bindless_model { + [[nodiscard]] device_buffer& get_uniform_buffer(enum UniformTypes type) const; + + void init(); + + void deinit(); + + VkPipelineLayout global_layout; + VkDescriptorSet global_set; + +public: + static constexpr size_t push_constant_slot_size = sizeof(uintptr_t); + static constexpr size_t push_constant_slots = 3U; + +private: + VkDescriptorSetLayout global_set_layout; + VkDescriptorPool descriptor_pool; + handle uniform_buffers[UniformTypes::MAX]; + + static constexpr size_t descriptor_pool_allocable_sets_count = 64U; + static constexpr uint32_t set_descriptors_count = 1024U; + + VkSampler samplers[SamplerType::MAX_SAMPLER]; + + static constexpr size_t globals_uniform_buffer_size = 64 * KB; + static constexpr size_t passes_uniform_buffer_size = 64 * KB; + static constexpr size_t draws_uniform_buffer_size = 64 * KB; +}; diff --git a/include/vk-command-buffer.hpp b/include/vk-command-buffer.hpp new file mode 100644 index 0000000..82d5439 --- /dev/null +++ b/include/vk-command-buffer.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "handle.hpp" +#include "vk-device-types.hpp" +#include "vec3.hpp" + +struct device_texture; +struct device_buffer; +struct device_pipeline; + +struct dispatch_params { + handle pipeline; + vec3u group_size; + vec3u local_group_size; +}; + +struct renderpass_params { +private: + struct rect { + int32_t x; + int32_t y; + uint32_t width; + uint32_t height; + }; + +public: + rect render_area; + std::span> color_attachments; +}; + +struct draw_params { + handle pipeline; + handle index_buffer; + uint32_t vertex_count; + uint32_t vertex_offset; + uint32_t instance_count; +}; + +struct draw_indexed_params { + handle pipeline; + handle index_buffer; + uint32_t vertex_count; + uint32_t vertex_offset; + uint32_t index_offset; + uint32_t instance_count; +}; + +struct command_buffer { + void start() const; + void stop() const; + + void barrier(handle texture_handle, VkPipelineStageFlags2 stage, VkAccessFlags2 access, VkImageLayout layout) const; + + void copy(handle buffer_handle, handle texture_handle, uint64_t offset = 0) const; + + VkCommandBuffer vk_command_buffer; + QueueType queue_type; +}; + +// General purpose queue +struct graphics_command_buffer: public command_buffer { + void dispatch(const dispatch_params& params) const; + + void begin_renderpass(const renderpass_params& params) const; + void draw(const draw_params& params) const; + void draw_indexed(const draw_indexed_params& params) const; + void end_renderpass() const; +}; + +struct compute_command_buffer: public command_buffer { + void dispatch(const dispatch_params& params); +}; + +struct transfer_command_buffer: public command_buffer { +}; diff --git a/include/vk-context.hpp b/include/vk-context.hpp deleted file mode 100644 index 0dfd256..0000000 --- a/include/vk-context.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include - -using VmaAllocator = struct VmaAllocator_T*; - -struct queue { - VkQueue handle; - uint32_t index; - VkQueueFlags usages; -}; - -class vkcontext { - public: - vkcontext(); - - ~vkcontext(); - - VkInstance instance; - - VkPhysicalDevice physical_device; - VkDevice device; - - VmaAllocator allocator; - - queue graphics_queue; - - private: - void create_instance(); - - void create_debugger(); - - void create_device(); - - void create_memory_allocator(); - - void select_physical_device(); - - [[nodiscard]] uint32_t select_queue(VkQueueFlags queue_usage) const; - - static void check_available_instance_layers(const char* needed_layers[], size_t needed_layers_count); - - static void check_available_instance_extensions(const char* needed_extensions[], size_t needed_extensions_count); - - static bool support_required_features(VkPhysicalDevice physical_device); - - - VkDebugUtilsMessengerEXT debugMessenger; -}; diff --git a/include/vk-device-types.hpp b/include/vk-device-types.hpp new file mode 100644 index 0000000..94f9560 --- /dev/null +++ b/include/vk-device-types.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include + +#include "freelist.hpp" + +using VmaAllocation = struct VmaAllocation_T*; + +enum class QueueType : uint32_t { + GRAPHICS, + ASYNC_COMPUTE, + TRANSFER, + MAX, +}; + +struct texture_desc { + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + VkImageUsageFlags usages; + VkFormat format; + VkImageType type; + VkImage vk_image = nullptr; + const char* name = nullptr; + + static constexpr auto max_mips = 16U; +}; + +struct device_texture { + void init(const texture_desc& desc); + + void release(); + + void create_views(); + + [[nodiscard]] uint32_t get_storage_index() const { + assert(storage_index.id != handle::invalid_id); + return storage_index.id; + } + + [[nodiscard]] uint32_t get_sampled_index() const { + assert(sampled_index.id != handle::invalid_id); + return sampled_index.id; + } + + VkImage vk_image = nullptr; + VkImageView whole_view = nullptr; + VkImageView mips_views[texture_desc::max_mips] = { nullptr }; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + VkPipelineStageFlags2 stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + VkAccessFlags2 access = VK_ACCESS_2_NONE; + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageAspectFlags aspects = VK_IMAGE_ASPECT_NONE_KHR; + + uint32_t width = 1U; + uint32_t height = 1U; + uint32_t depth = 1U; + uint32_t mips = 1U; + + const char* name = nullptr; + + private: + handle storage_index; + handle sampled_index; + + VmaAllocation alloc = nullptr; + + static idlist<> storage_indices; + static idlist<> sampled_indices; +}; + + +struct sampler_desc { + VkFilter mag_filter = VK_FILTER_NEAREST; + VkFilter min_filter = VK_FILTER_NEAREST; + VkSamplerMipmapMode mipmap_mode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + VkSamplerAddressMode address_mode_u = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_v = VK_SAMPLER_ADDRESS_MODE_REPEAT; + VkSamplerAddressMode address_mode_w = VK_SAMPLER_ADDRESS_MODE_REPEAT; + float mip_lod_bias = 0.f; + VkBool32 anisotropy = VK_FALSE; + float max_anisotropy = 0.f; + VkBool32 compare_enabled = VK_FALSE; + VkCompareOp compare_op = VK_COMPARE_OP_NEVER; + float min_lod = 0.f; + float max_lod = 0.f; + VkBorderColor border_color = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + VkBool32 unnomalized_coords = VK_FALSE; +}; + +struct device_sampler { + void init(const sampler_desc& desc); + + VkSampler vk_sampler = nullptr; + + [[nodiscard]] uint32_t get_sampler_index() const { + return sampler_index.id; + } + + private: + handle sampler_index; + + static idlist<> sampler_indices; +}; + + +struct buffer_desc { + size_t size; + VkBufferUsageFlags usages; + VkMemoryPropertyFlags memory_properties; + uint32_t memory_usage; + const char* name; +}; + +struct device_buffer { + template + T* allocate() { + u32 alloc_size = sizeof(T); + if (allocated_size + alloc_size > size) { + reset(); + } + + offset = allocated_size; + T* addr = (T*)(static_cast(mapped_ptr) + offset); + allocated_size += alloc_size; + return addr; + } + + void* allocate(u32 alloc_size) { + if (allocated_size + alloc_size > size) { + reset(); + } + + offset = allocated_size; + void* addr = (void*)(static_cast(mapped_ptr) + offset); + allocated_size += alloc_size; + return addr; + } + + void reset() { + allocated_size = 0U; + offset = 0U; + } + + u32 offset = 0U; + u32 allocated_size = 0U; + VkBuffer vk_buffer; + VmaAllocation alloc; + VkDeviceAddress device_address = 0U; + void* mapped_ptr; + size_t size; + VkBufferUsageFlagBits2 usages; + + const char* name; +}; + +struct graphics_pipeline_desc { + uint8_t* vs_code; + size_t vs_code_size; + uint8_t* fs_code; + size_t fs_code_size; + std::span color_attachments_format; + VkFormat depth_attachment_format; + VkFormat stencil_attachment_format; + const char* name; +}; + +struct compute_pipeline_desc { + uint8_t* cs_code; + size_t cs_code_size; + const char* name; +}; + +struct device_pipeline { + VkPipeline vk_pipeline; + VkPipelineBindPoint bind_point; +}; + +struct semaphore_desc { + VkSemaphoreType type; + uint64_t initial_value = 0U; +}; + +struct device_semaphore { + VkSemaphore vk_semaphore = nullptr; + uint64_t value; +}; + + +typedef struct HWND__* HWND; + +struct surface_desc { + HWND window_handle; + VkSurfaceFormatKHR surface_format; + VkPresentModeKHR present_mode; + VkImageUsageFlags usages; + uint32_t image_count = surface_desc::default_image_count; + + static constexpr uint32_t max_image_count = 3U; + static constexpr uint32_t default_image_count = 3U; +}; + +struct device_surface { + VkSurfaceKHR vk_surface; + VkSwapchainKHR vk_swapchain; + VkSurfaceFormatKHR surface_format; + + handle swapchain_images[surface_desc::max_image_count]; + uint32_t image_index; + uint32_t image_count; + uint32_t frame_index = 0U; + + handle acquire_semaphores[surface_desc::max_image_count]; + handle submit_semaphores[surface_desc::max_image_count]; + + uint32_t acquire_image_index(); +}; diff --git a/include/vk-device.hpp b/include/vk-device.hpp new file mode 100644 index 0000000..e2e8c99 --- /dev/null +++ b/include/vk-device.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include "freelist.hpp" +#include "vk-bindless.hpp" +#include "vk-command-buffer.hpp" + +using VmaAllocator = struct VmaAllocator_T*; + +struct command_buffer; +class window; + +class vkdevice { + struct queue { + VkQueue vk_queue = VK_NULL_HANDLE; + uint32_t index = UINT32_MAX; + VkQueueFlags usages; + VkCommandPool command_pool = VK_NULL_HANDLE; + }; + + public: + void init(); + void deinit(); + + static inline vkdevice& get() { + return render_device; + } + + handle create_texture(const texture_desc& desc); + + handle create_sampler(const sampler_desc& desc); + + handle create_buffer(const buffer_desc& desc); + + handle create_graphics_pipeline(const graphics_pipeline_desc& desc); + + handle create_compute_pipeline(const compute_pipeline_desc& desc); + + handle create_surface(const surface_desc& desc); + + handle create_semaphore(const semaphore_desc& desc, const char* name); + + void destroy_texture(handle handle); + + void destroy_sampler(handle handle); + + void destroy_buffer(handle handle); + + void destroy_pipeline(handle handle); + + void destroy_semaphore(handle handle); + + void destroy_surface(handle handle); + + template + void allocate_command_buffers(buffer_type* buffers, size_t count, QueueType queue_type, const char* name) { + allocate_command_buffers(static_cast(buffers), count, queue_type, name); + } + + [[nodiscard]] inline device_texture& get_texture(handle handle) { + return textures[handle]; + } + + [[nodiscard]] inline device_sampler& get_sampler(handle handle) { + return samplers[handle]; + } + + [[nodiscard]] inline device_buffer& get_buffer(handle handle) { + return buffers[handle]; + } + + [[nodiscard]] inline const device_pipeline& get_pipeline(handle handle) const { + return pipelines[handle]; + } + + [[nodiscard]] inline device_surface& get_surface(handle handle) { + return surfaces[handle]; + } + + [[nodiscard]] inline device_semaphore& get_semaphore(handle handle) { + return semaphores[handle]; + } + + [[nodiscard]] inline const bindless_model& get_bindingmodel() const { + return bindless; + } + + const freelist& get_textures() const { + return textures; + } + + inline VkDevice get_device() const { + return device; + } + + inline VmaAllocator get_allocator() { + return gpu_allocator; + } + + inline const VkPhysicalDeviceLimits& get_device_limits() const { + return physical_device_props.properties.limits; + } + + // uint64_t submit(std::span buffers, handle wait_handle, handle signal_handle, handle fence_handle); + uint32_t acquire_image_index(handle surface_handle); + uint64_t submit_before_present(handle surface_handle, command_buffer* buffers, uint32_t count); + uint64_t submit(command_buffer* buffers, uint32_t count); + + void present(handle surface_handle); + + void wait(); + + private: + vkdevice() = default; + ~vkdevice() = default; + + void allocate_command_buffers(command_buffer* buffers, size_t count, QueueType type, const char* name); + + void create_swapchain(const surface_desc& desc, device_surface& surface); + + // TODO: Wrap in a struct called adapter ? + void create_instance(); + + void create_device(); + + void create_memory_allocator(); + + void create_command_pools(); + + void pick_physical_device(); + + bool device_support_features(VkPhysicalDevice physical_dev); + + void create_debug_layer_callback(); + + queue queues[static_cast(QueueType::MAX)]; + + VkInstance instance; + VkPhysicalDevice physical_device; + VkPhysicalDeviceProperties2 physical_device_props; + VkDevice device; + + VmaAllocator gpu_allocator; + + bindless_model bindless; + + static constexpr size_t max_allocable_command_buffers = 16; + static constexpr size_t max_submitable_command_buffers = 16; + + freelist textures; + freelist samplers; + freelist buffers; + freelist pipelines; + freelist surfaces; + freelist semaphores; + + device_semaphore timeline_semaphore; + + static vkdevice render_device; + +#ifdef _DEBUG + VkDebugUtilsMessengerEXT debug_messenger; +#endif // _DEBUG +}; diff --git a/include/vk-renderer.hpp b/include/vk-renderer.hpp deleted file mode 100644 index 1317912..0000000 --- a/include/vk-renderer.hpp +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef __VK_RENDERER_HPP_ -#define __VK_RENDERER_HPP_ - -#include -#include -#include - -#include "vk-context.hpp" -#include "vk-api.hpp" - - -class Renderpass; -class ComputeRenderpass; -class PrimitiveRenderpass; -class Primitive; -class window; - -class Texture; -class Sampler; -class RingBuffer; - - -class Buffer { - public: - - Buffer(size_t size, VkBufferUsageFlagBits usage); - ~Buffer(); - - void write(void* data, off_t alloc_offset, size_t data_size) const; - - void resize(size_t new_size); - - handle device_buffer; - - size_t buffer_size; - - VkBufferUsageFlagBits usage; -}; - - -class vkrenderer { - public: - vkrenderer(window& wnd); - - ~vkrenderer(); - - void recreate_swapchain(); - - - void update_images(); - - void begin_frame(); - - void finish_frame(); - - static void queue_image_update(Texture* texture); - - static Buffer* create_buffer(size_t size); - - static Buffer* create_index_buffer(size_t size); - - static Buffer* create_staging_buffer(size_t size); - - static Sampler* create_sampler(VkFilter filter, VkSamplerAddressMode address_mode); - - - ComputeRenderpass* create_compute_renderpass(); - - PrimitiveRenderpass* create_primitive_renderpass(); - - Primitive* create_primitive(PrimitiveRenderpass& primitive_render_pass); - - void render(); - - [[nodiscard]]uint32_t frame_index() const { return this->virtual_frame_index; } - - [[nodiscard]]Texture* back_buffer() const { return swapchain_textures[swapchain_image_index]; } - - [[nodiscard]]VkFormat back_buffer_format() const { return swapchain.surface_format.format; } - - static constexpr uint32_t virtual_frames_count = 2; - - static vkcontext context; - - static vkapi api; - - private: - - - void handle_swapchain_result(VkResult function_result); - - std::vector renderpasses; - - uint32_t virtual_frame_index = 0; - uint32_t swapchain_image_index = 0; - - VkCommandBuffer graphics_command_buffers[virtual_frames_count]; - VkCommandBuffer copy_command_buffers[virtual_frames_count]; - - RingBuffer* staging_buffers[virtual_frames_count]; - - - pipeline tonemapping_pipeline; - - VkFence submission_fences[virtual_frames_count]; - VkSemaphore execution_semaphores[virtual_frames_count]; - VkSemaphore acquire_semaphores[virtual_frames_count]; - - VkCommandPool graphics_command_pool; - VkCommandPool copy_command_pools[virtual_frames_count]; - - VkSurfaceKHR platform_surface; - swapchain swapchain; - std::vector swapchain_textures; - std::vector recorded_command_buffers; - - const uint32_t min_swapchain_image_count = 3; - - static std::vector upload_queue; -}; - -class RingBuffer { - public: - - static const size_t invalid_alloc = -1; - - RingBuffer(size_t size); - - [[nodiscard]]size_t alloc(size_t alloc_size) { - assert(alloc_size > 0 && alloc_size <= buffer_size); - - auto alloc_offset = ptr; - - if (alloc_offset <= buffer_size - alloc_size) { - ptr += alloc_size; - return alloc_offset; - } - - return invalid_alloc; - } - - void write(void* data, size_t alloc_offset, size_t data_size) const { - auto api_buffer = vkrenderer::api.get_buffer(device_buffer); - - std::memcpy((uint8_t*)api_buffer.device_ptr + alloc_offset, data, data_size); - } - - void reset() { - ptr = 0; - } - - handle device_buffer; - - size_t buffer_size; - size_t ptr = 0; -}; - -class Sampler { - public: - - handle device_sampler; -}; - -#endif // !__VK_RENDERER_HPP_ diff --git a/include/vk-utils.hpp b/include/vk-utils.hpp new file mode 100644 index 0000000..f26d2a3 --- /dev/null +++ b/include/vk-utils.hpp @@ -0,0 +1,12 @@ +#pragma once + +#ifdef _DEBUG +#define VKCHECK(result) assert((result) == VK_SUCCESS) +#else +#define VKCHECK(result) (void)result +#endif + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + void*); -- cgit v1.3