From 3c0dcb672ec782df8b33d463661f34f287fc4aac Mon Sep 17 00:00:00 2001 From: light7734 Date: Fri, 7 Nov 2025 22:59:33 +0330 Subject: [PATCH] wip: convert from include style to module import style :D --- modules/renderer/CMakeLists.txt | 45 +- modules/renderer/api.cppm | 14 + modules/renderer/backends/factory.cppm | 85 ++ .../vk/context/device.cppm} | 358 +++++-- modules/renderer/backends/vk/context/gpu.cppm | 125 +++ .../backends/vk/context/instance.cppm | 149 +++ .../vk/context/instance.test.cpp | 0 .../renderer/backends/vk/context/surface.cppm | 64 ++ .../vk/context/swapchain.cppm} | 90 ++ .../vk/data/buffer.cppm} | 62 ++ .../vk/data/descriptors.cppm} | 0 .../renderer/backends/vk/library_wrapper.cppm | 951 ++++++++++++++++++ .../backends/vk/library_wrapper.cppma | 102 ++ .../vk/messenger.cppm} | 56 +- .../vk/messenger.test.cpp | 0 .../raii/raii.hpp => backends/vk/raii.cppm} | 2 +- .../backend => backends}/vk/renderer/pass.cpp | 0 .../vk/renderer/pass.cppm} | 0 .../vk/renderer/renderer.cpp | 0 .../vk/renderer/renderer.cppm} | 0 modules/renderer/backends/vk/utils.cppm | 8 + .../components/sprite.hpp => components.cppm} | 32 +- .../data/frame_constants.hpp => data.cppm} | 4 +- .../context/device.cppm} | 9 +- .../frontend/context/device.test.cpp | 0 .../gpu.hpp => frontend/context/gpu.cppm} | 10 +- .../context/instance.cppm} | 9 +- .../context/surface.cppm} | 19 +- .../frontend/context/surface.test.cpp | 0 .../context/swapchain.cppm} | 25 + .../{private => }/frontend/data/buffer.cpp | 0 .../buffer.hpp => frontend/data/buffer.cppm} | 0 .../frontend/data/buffer.test.cpp | 0 .../messenger.hpp => frontend/messenger.cppm} | 47 +- .../{private => }/frontend/renderer/pass.cpp | 0 .../pass.hpp => frontend/renderer/pass.cppm} | 0 .../frontend/renderer/pass.test.cpp | 0 .../frontend/renderer/renderer.cpp | 0 .../renderer/renderer.cppm} | 0 .../frontend/renderer/renderer.test.cpp | 0 .../private/backend/vk/context/device.hpp | 260 ----- .../private/backend/vk/context/gpu.cpp | 80 -- .../private/backend/vk/context/gpu.hpp | 61 -- .../private/backend/vk/context/instance.cpp | 457 --------- .../private/backend/vk/context/instance.hpp | 83 -- .../private/backend/vk/context/surface.cpp | 40 - .../private/backend/vk/context/surface.hpp | 43 - .../private/backend/vk/context/swapchain.hpp | 89 -- .../private/backend/vk/data/buffer.hpp | 60 -- .../renderer/private/backend/vk/messenger.hpp | 49 - modules/renderer/private/backend/vk/utils.hpp | 17 - .../renderer/private/backend/vk/vulkan.hpp | 104 -- .../private/frontend/context/device.cpp | 21 - .../renderer/private/frontend/context/gpu.cpp | 18 - .../private/frontend/context/instance.cpp | 17 - .../frontend/context/instance.test.cpp | 0 .../private/frontend/context/surface.cpp | 24 - .../private/frontend/context/swapchain.cpp | 23 - .../frontend/context/swapchain.test.cpp | 0 .../renderer/private/frontend/messenger.cpp | 30 - .../private/frontend/messenger.test.cpp | 0 modules/renderer/private/test/constants.hpp | 5 - modules/renderer/private/test/formatters.hpp | 0 modules/renderer/private/test/utils.cpp | 0 modules/renderer/public/api.hpp | 14 - .../renderer/public/components/messenger.hpp | 0 modules/renderer/public/components/skybox.hpp | 5 - modules/renderer/public/system.hpp | 107 -- .../{private/system.cpp => system.cppm} | 115 ++- .../renderer/{private => }/system.test.cpp | 0 .../test/utils.hpp => test/utils.cppm} | 49 +- 71 files changed, 2222 insertions(+), 1815 deletions(-) create mode 100644 modules/renderer/api.cppm create mode 100644 modules/renderer/backends/factory.cppm rename modules/renderer/{private/backend/vk/context/device.cpp => backends/vk/context/device.cppm} (62%) create mode 100644 modules/renderer/backends/vk/context/gpu.cppm create mode 100644 modules/renderer/backends/vk/context/instance.cppm rename modules/renderer/{private/backend => backends}/vk/context/instance.test.cpp (100%) create mode 100644 modules/renderer/backends/vk/context/surface.cppm rename modules/renderer/{private/backend/vk/context/swapchain.cpp => backends/vk/context/swapchain.cppm} (71%) rename modules/renderer/{private/backend/vk/data/buffer.cpp => backends/vk/data/buffer.cppm} (66%) rename modules/renderer/{private/backend/vk/data/descriptors.hpp => backends/vk/data/descriptors.cppm} (100%) create mode 100644 modules/renderer/backends/vk/library_wrapper.cppm create mode 100644 modules/renderer/backends/vk/library_wrapper.cppma rename modules/renderer/{private/backend/vk/messenger.cpp => backends/vk/messenger.cppm} (76%) rename modules/renderer/{private/backend => backends}/vk/messenger.test.cpp (100%) rename modules/renderer/{private/backend/vk/raii/raii.hpp => backends/vk/raii.cppm} (98%) rename modules/renderer/{private/backend => backends}/vk/renderer/pass.cpp (100%) rename modules/renderer/{private/backend/vk/renderer/pass.hpp => backends/vk/renderer/pass.cppm} (100%) rename modules/renderer/{private/backend => backends}/vk/renderer/renderer.cpp (100%) rename modules/renderer/{private/backend/vk/renderer/renderer.hpp => backends/vk/renderer/renderer.cppm} (100%) create mode 100644 modules/renderer/backends/vk/utils.cppm rename modules/renderer/{public/components/sprite.hpp => components.cppm} (67%) rename modules/renderer/{public/data/frame_constants.hpp => data.cppm} (66%) rename modules/renderer/{private/frontend/context/device.hpp => frontend/context/device.cppm} (61%) rename modules/renderer/{private => }/frontend/context/device.test.cpp (100%) rename modules/renderer/{private/frontend/context/gpu.hpp => frontend/context/gpu.cppm} (59%) rename modules/renderer/{private/frontend/context/instance.hpp => frontend/context/instance.cppm} (68%) rename modules/renderer/{private/frontend/context/surface.hpp => frontend/context/surface.cppm} (56%) rename modules/renderer/{private => }/frontend/context/surface.test.cpp (100%) rename modules/renderer/{private/frontend/context/swapchain.hpp => frontend/context/swapchain.cppm} (52%) rename modules/renderer/{private => }/frontend/data/buffer.cpp (100%) rename modules/renderer/{private/frontend/data/buffer.hpp => frontend/data/buffer.cppm} (100%) rename modules/renderer/{private => }/frontend/data/buffer.test.cpp (100%) rename modules/renderer/{public/frontend/messenger.hpp => frontend/messenger.cppm} (53%) rename modules/renderer/{private => }/frontend/renderer/pass.cpp (100%) rename modules/renderer/{private/frontend/renderer/pass.hpp => frontend/renderer/pass.cppm} (100%) rename modules/renderer/{private => }/frontend/renderer/pass.test.cpp (100%) rename modules/renderer/{private => }/frontend/renderer/renderer.cpp (100%) rename modules/renderer/{private/frontend/renderer/renderer.hpp => frontend/renderer/renderer.cppm} (100%) rename modules/renderer/{private => }/frontend/renderer/renderer.test.cpp (100%) delete mode 100644 modules/renderer/private/backend/vk/context/device.hpp delete mode 100644 modules/renderer/private/backend/vk/context/gpu.cpp delete mode 100644 modules/renderer/private/backend/vk/context/gpu.hpp delete mode 100644 modules/renderer/private/backend/vk/context/instance.cpp delete mode 100644 modules/renderer/private/backend/vk/context/instance.hpp delete mode 100644 modules/renderer/private/backend/vk/context/surface.cpp delete mode 100644 modules/renderer/private/backend/vk/context/surface.hpp delete mode 100644 modules/renderer/private/backend/vk/context/swapchain.hpp delete mode 100644 modules/renderer/private/backend/vk/data/buffer.hpp delete mode 100644 modules/renderer/private/backend/vk/messenger.hpp delete mode 100644 modules/renderer/private/backend/vk/utils.hpp delete mode 100644 modules/renderer/private/backend/vk/vulkan.hpp delete mode 100644 modules/renderer/private/frontend/context/device.cpp delete mode 100644 modules/renderer/private/frontend/context/gpu.cpp delete mode 100644 modules/renderer/private/frontend/context/instance.cpp delete mode 100644 modules/renderer/private/frontend/context/instance.test.cpp delete mode 100644 modules/renderer/private/frontend/context/surface.cpp delete mode 100644 modules/renderer/private/frontend/context/swapchain.cpp delete mode 100644 modules/renderer/private/frontend/context/swapchain.test.cpp delete mode 100644 modules/renderer/private/frontend/messenger.cpp delete mode 100644 modules/renderer/private/frontend/messenger.test.cpp delete mode 100644 modules/renderer/private/test/constants.hpp delete mode 100644 modules/renderer/private/test/formatters.hpp delete mode 100644 modules/renderer/private/test/utils.cpp delete mode 100644 modules/renderer/public/api.hpp delete mode 100644 modules/renderer/public/components/messenger.hpp delete mode 100644 modules/renderer/public/components/skybox.hpp delete mode 100644 modules/renderer/public/system.hpp rename modules/renderer/{private/system.cpp => system.cppm} (61%) rename modules/renderer/{private => }/system.test.cpp (100%) rename modules/renderer/{private/test/utils.hpp => test/utils.cppm} (86%) diff --git a/modules/renderer/CMakeLists.txt b/modules/renderer/CMakeLists.txt index e514beb..1e75aed 100644 --- a/modules/renderer/CMakeLists.txt +++ b/modules/renderer/CMakeLists.txt @@ -1,26 +1,27 @@ add_library_module( + NAME renderer - system.cpp - # Vulkan - backend - backend/vk/messenger.cpp - backend/vk/context/device.cpp - backend/vk/context/gpu.cpp - backend/vk/context/instance.cpp - backend/vk/context/surface.cpp - backend/vk/context/swapchain.cpp - backend/vk/data/buffer.cpp - backend/vk/renderer/pass.cpp - backend/vk/renderer/renderer.cpp - # frontend - frontend/messenger.cpp - frontend/context/device.cpp - frontend/context/gpu.cpp - frontend/context/instance.cpp - frontend/context/surface.cpp - frontend/context/swapchain.cpp - frontend/data/buffer.cpp - frontend/renderer/renderer.cpp - frontend/renderer/pass.cpp) + INTERFACES + # system.cppm Vulkan - backend + api.cppm + # backends/vk/messenger.cppm + backends/factory.cppm + # backends/vk/library_loader.cppm + backends/vk/library_wrapper.cppm + backends/vk/context/device.cppm + backends/vk/context/gpu.cppm + backends/vk/context/instance.cppm + backends/vk/context/surface.cppm + # backends/vk/context/swapchain.cppm backends/vk/data/buffer.cppm + # backends/vk/renderer/pass.cppm backends/vk/renderer/renderer.cppm frontend + # frontend/messenger.cppm + frontend/context/device.cppm + frontend/context/gpu.cppm + frontend/context/instance.cppm + frontend/context/surface.cppm + # frontend/context/swapchain.cppm frontend/data/buffer.cppm + # frontend/renderer/renderer.cppm frontend/renderer/pass.cppm +) target_link_libraries( renderer @@ -33,6 +34,8 @@ target_link_libraries( camera PRIVATE surface pthread) +return() + add_test_module( renderer test/utils.cpp diff --git a/modules/renderer/api.cppm b/modules/renderer/api.cppm new file mode 100644 index 0000000..f18c84f --- /dev/null +++ b/modules/renderer/api.cppm @@ -0,0 +1,14 @@ +export module renderer.api; +import std; + +namespace lt::renderer { + +export enum class Api: std::uint8_t { + none = 0u, + + vulkan, + direct_x, + metal, +}; + +} diff --git a/modules/renderer/backends/factory.cppm b/modules/renderer/backends/factory.cppm new file mode 100644 index 0000000..8931ac5 --- /dev/null +++ b/modules/renderer/backends/factory.cppm @@ -0,0 +1,85 @@ +export module renderer.backend.factory; +import memory.scope; +import renderer.frontend.device; +import renderer.backend.vk.device; +import debug.assertions; +import ecs.entity; +import renderer.backend.vk.instance; +import renderer.backend.vk.gpu; +import renderer.backend.vk.surface; +import renderer.frontend.instance; +import renderer.frontend.surface; +import renderer.frontend.gpu; +import renderer.api; +import std; + +export namespace lt::renderer { + +[[nodiscard]] auto get_instance(Api target_api) -> IInstance *; + +[[nodiscard]] auto create_surface( + Api target_api, + IInstance *instance, + const ecs::Entity &surface_entity +); + +[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope; + +} // namespace lt::renderer + +module :private; +using namespace lt; +using namespace lt::renderer; + +[[nodiscard]] auto get_instance(Api target_api) -> IInstance * +{ + switch (target_api) + { + case Api::vulkan: return vkb::Instance::get(); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } +} + +[[nodiscard]] auto create_surface( + Api target_api, + class IInstance *instance, + const lt::ecs::Entity &surface_entity +) -> memory::Scope +{ + debug::ensure(instance, "Failed to create renderer::ISurface: null instance"); + + switch (target_api) + { + case Api::vulkan: return memory::create_scope(instance, surface_entity); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } +} + +[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope +{ + switch (target_api) + { + case Api::vulkan: return memory::create_scope(instance); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } +} + +[[nodiscard]] auto create_device(Api target_api, IGpu *gpu, ISurface *surface) + -> memory::Scope +{ + debug::ensure(gpu, "Failed to create renderer::IDevice: null gpu"); + debug::ensure(surface, "Failed to create renderer::IDevice: null surface"); + + switch (target_api) + { + case Api::vulkan: return memory::create_scope(gpu, surface); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } diff --git a/modules/renderer/private/backend/vk/context/device.cpp b/modules/renderer/backends/vk/context/device.cppm similarity index 62% rename from modules/renderer/private/backend/vk/context/device.cpp rename to modules/renderer/backends/vk/context/device.cppm index 15f09c5..d27d9e9 100644 --- a/modules/renderer/private/backend/vk/context/device.cpp +++ b/modules/renderer/backends/vk/context/device.cppm @@ -1,3 +1,252 @@ +export module renderer.backend.vk.device; + +#include +#include +#include +#include +#include + +namespace lt::renderer::vk { + +class Device: public IDevice +{ +public: + Device(IGpu *gpu, ISurface *surface); + [[nodiscard]] auto vk() const -> VkDevice + { + return m_device; + } + + [[nodiscard]] auto get_family_indices() const -> std::array + { + return { m_graphics_queue_family_index, m_present_queue_family_index }; + } + + [[nodiscard]] auto get_graphics_queue() const -> VkQueue + { + return m_graphics_queue; + } + + [[nodiscard]] auto get_present_queue() const -> VkQueue + { + return m_present_queue; + } + + /** utilities */ + template + void name(const T &object, std::format_string fmt, Args &&...args) + { + const auto name = std::format(fmt, std::forward(args)...); + auto info = VkDebugUtilsObjectNameInfoEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .objectType = get_object_type(object), + .objectHandle = (uint64_t)(object), + .pObjectName = name.c_str(), + }; + + vk_set_debug_object_name(m_device, &info); + } + + template + void name(const T &object, const char *name) + { + auto info = VkDebugUtilsObjectNameInfoEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .objectType = get_object_type(object), + .objectHandle = (uint64_t)(object), + .pObjectName = name, + }; + + vk_set_debug_object_name(m_device, &info); + } + + + /** work functions */ + void submit(VkSubmitInfo info, VkFence fence) const; + + void present(VkPresentInfoKHR info) const; + + void wait_idle() const; + + void wait_for_fence(VkFence fence) const; + + void wait_for_fences(std::span fences) const; + + void reset_fence(VkFence fence) const; + + void reset_fences(std::span fences) const; + + /** getter functions */ + [[nodiscard]] auto acquire_image( + VkSwapchainKHR swapchain, + VkSemaphore semaphore, + uint64_t timeout = 100'000'000 + ) -> std::optional; + + [[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector; + + [[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements; + + /** binders / mappers */ + void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const; + + [[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const + -> std::span; + + void unmap_memory(VkDeviceMemory memory); + + /** create functions */ + [[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR; + + [[nodiscard]] auto create_framebuffer(VkFramebufferCreateInfo info) const -> VkFramebuffer; + + [[nodiscard]] auto create_image_view(VkImageViewCreateInfo info) const -> VkImageView; + + [[nodiscard]] auto create_graphics_pipeline(VkGraphicsPipelineCreateInfo info) const + -> VkPipeline; + + [[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass; + + [[nodiscard]] auto create_pipeline_layout( + std::vector descriptor_set_layout, + std::vector push_constant_ranges + ) const -> VkPipelineLayout; + + [[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule; + + [[nodiscard]] auto create_command_pool(VkCommandPoolCreateInfo info) const -> VkCommandPool; + + [[nodiscard]] auto create_semaphores(uint32_t count) const -> std::vector; + + [[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const + -> std::vector; + + [[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer; + + [[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const + -> VkDescriptorSetLayout; + + [[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const + -> VkDescriptorPool; + + /** allocation functions */ + [[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory; + + [[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const + -> std::vector; + + [[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const + -> VkDescriptorSet; + + /** de-allocation functions */ + void free_memory(VkDeviceMemory memory) const; + + void free_descriptor_set( + VkDescriptorPool descriptor_pool, + VkDescriptorSet descriptor_set + ) const; + + /** destroy functions */ + void destroy_swapchain(VkSwapchainKHR swapchain) const; + + void destroy_framebuffer(VkFramebuffer framebuffer) const; + + void destroy_framebuffers(std::span framebuffers) const; + + void destroy_image_view(VkImageView image_view) const; + + void destroy_image_views(std::span image_views) const; + + void destroy_pipeline(VkPipeline pipeline) const; + + void destroy_pass(VkRenderPass pass) const; + + void destroy_pipeline_layout(VkPipelineLayout pipeline_layout) const; + + void destroy_shader_module(VkShaderModule shader_module) const; + + void destroy_command_pool(VkCommandPool command_pool) const; + + void destroy_semaphore(VkSemaphore semaphore) const; + + void destroy_semaphores(std::span semaphores) const; + + void destroy_fence(VkFence fence) const; + + void destroy_fences(std::span fences) const; + + void destroy_buffer(VkBuffer buffer) const; + + void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const; + + void destroy_descriptor_pool(VkDescriptorPool pool) const; + +private: + template + static auto get_object_type(const T &object) -> VkObjectType + { + std::ignore = object; + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_QUEUE; + } + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_FENCE; + } + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_SEMAPHORE; + } + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_SWAPCHAIN_KHR; + } + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_IMAGE; + } + + if constexpr (std::is_same_v) + { + return VK_OBJECT_TYPE_IMAGE_VIEW; + } + + static_assert("invalid type"); + } + + + void initialize_physical_device(); + + void initialize_logical_device(); + + void initialize_queue_indices(); + + [[nodiscard]] auto find_suitable_queue_family() const -> uint32_t; + + vk::Gpu m_gpu {}; + + vk::Surface *m_surface {}; + + vk::Device m_device; + + vk::Queue m_graphics_queue; + + vk::Queue m_present_queue; + + std::uint32_t m_graphics_queue_family_index = vk::constants::queue_family_ignored; + + std::uint32_t m_present_queue_family_index = vk::constants::queue_family_ignored; +}; + +} // namespace lt::renderer::vk + + // #include #include @@ -58,7 +307,6 @@ void Device::initialize_logical_device() const float priorities = .0f; auto queue_infos = std::vector {}; - auto queue_families = std::set { m_graphics_queue_family_index, m_present_queue_family_index }; for (auto queue_family : queue_families) { @@ -81,91 +329,25 @@ void Device::initialize_logical_device() }; auto descriptor_indexing_features = m_gpu->get_descriptor_indexing_features(); - log::debug(""); - - log::debug( - "shaderInputAttachmentArrayDynamicIndexing: {}", - descriptor_indexing_features.shaderInputAttachmentArrayDynamicIndexing - ); - log::debug( - " shaderUniformTexelBufferArrayDynamicIndexing: {}", - descriptor_indexing_features.shaderUniformTexelBufferArrayDynamicIndexing - ); - log::debug( - " shaderStorageTexelBufferArrayDynamicIndexing: {}", - descriptor_indexing_features.shaderStorageTexelBufferArrayDynamicIndexing - ); - log::debug( - " shaderUniformBufferArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderUniformBufferArrayNonUniformIndexing - ); - log::debug( - " shaderSampledImageArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderSampledImageArrayNonUniformIndexing - ); - log::debug( - " shaderStorageBufferArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderStorageBufferArrayNonUniformIndexing - ); - log::debug( - " shaderStorageImageArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderStorageImageArrayNonUniformIndexing - ); - log::debug( - " shaderInputAttachmentArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderInputAttachmentArrayNonUniformIndexing - ); - log::debug( - " shaderUniformTexelBufferArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderUniformTexelBufferArrayNonUniformIndexing - ); - log::debug( - " shaderStorageTexelBufferArrayNonUniformIndexing: {}", - descriptor_indexing_features.shaderStorageTexelBufferArrayNonUniformIndexing - ); - log::debug( - " descriptorBindingUniformBufferUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingUniformBufferUpdateAfterBind - ); - log::debug( - " descriptorBindingSampledImageUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingSampledImageUpdateAfterBind - ); - log::debug( - " descriptorBindingStorageImageUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingStorageImageUpdateAfterBind - ); - log::debug( - " descriptorBindingStorageBufferUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingStorageBufferUpdateAfterBind - ); - log::debug( - " descriptorBindingUniformTexelBufferUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingUniformTexelBufferUpdateAfterBind - ); - log::debug( - " descriptorBindingStorageTexelBufferUpdateAfterBind: {}", - descriptor_indexing_features.descriptorBindingStorageTexelBufferUpdateAfterBind - ); - log::debug( - " descriptorBindingUpdateUnusedWhilePending: {}", - descriptor_indexing_features.descriptorBindingUpdateUnusedWhilePending - ); - log::debug( - " descriptorBindingPartiallyBound: {}", - descriptor_indexing_features.descriptorBindingPartiallyBound - ); - log::debug( - " descriptorBindingVariableDescriptorCount: {}", - descriptor_indexing_features.descriptorBindingVariableDescriptorCount - ); - log::debug(" runtimeDescriptorArray: {}", descriptor_indexing_features.runtimeDescriptorArray); const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, .pNext = &descriptor_indexing_features, .dynamicRendering = true, }; + auto queue_indices = std::set { m_graphics_queue_family_index, m_present_queue_family_index }; + m_device = vk::Device( + vk::Device::CreateInfo { + .queue_indices = queue_indices, + .extensions = { + vk::constants::device_extension_names::swapchain, + vk::constants::device_extension_names::dynamic_rendering, + vk::constants::device_extension_names::descriptor_indexing, + + } + + } + ); m_device = m_gpu->create_device( VkDeviceCreateInfo { @@ -185,18 +367,18 @@ void Device::initialize_queue_indices() auto properties = m_gpu->get_queue_family_properties(); for (auto idx = uint32_t { 0u }; const auto &property : properties) { - if (property.queueFlags & VK_QUEUE_GRAPHICS_BIT) + if (property.queue_flags & vk::QueueFlags::graphics_bit) { m_graphics_queue_family_index = idx; } - if (m_gpu->queue_family_supports_presentation(m_surface->vk(), idx)) + if (m_gpu->queue_family_supports_surface(m_surface->vk(), idx)) { m_present_queue_family_index = idx; } - if (m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED - && m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED) + if (m_graphics_queue_family_index != vk::constants::queue_family_ignored + && m_present_queue_family_index != vk::constants::queue_family_ignored) { break; } @@ -204,13 +386,13 @@ void Device::initialize_queue_indices() ++idx; } - ensure( - m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED, + debug::ensure( + m_graphics_queue_family_index != vk::constants::queue_family_ignored, "Failed to find graphics queue family" ); - ensure( - m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED, + debug::ensure( + m_present_queue_family_index != vk::constants::queue_family_ignored, "Failed to find presentation queue family" ); } diff --git a/modules/renderer/backends/vk/context/gpu.cppm b/modules/renderer/backends/vk/context/gpu.cppm new file mode 100644 index 0000000..b96afe3 --- /dev/null +++ b/modules/renderer/backends/vk/context/gpu.cppm @@ -0,0 +1,125 @@ +export module renderer.backend.vk.gpu; +import renderer.backend.vk.library_wrapper; +import debug.assertions; +import renderer.frontend.instance; +import renderer.frontend.gpu; +import renderer.backend.vk.instance; +import memory.null_on_move; +import std; + +namespace lt::renderer::vkb { + +export class Gpu: public IGpu +{ +public: + Gpu(IInstance *instance); + + // [[nodiscard]] auto queue_family_supports_presentation( + // VkSurfaceKHR surface, + // uint32_t queue_family_idx + // ) -> bool; + // + // [[nodiscard]] auto get_surface_capabilities(VkSurfaceKHR surface) const + // -> VkSurfaceCapabilitiesKHR; + // + // [[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const + // -> std::vector; + // + // [[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties + // { + // return m_properties; + // } + // + // [[nodiscard]] auto get_descriptor_indexing_features() const + // -> VkPhysicalDeviceDescriptorIndexingFeatures + // { + // return m_descriptor_indexing_features; + // } + // + // [[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties + // { + // return m_memory_properties; + // } + // + // [[nodiscard]] auto get_queue_family_properties() const -> + // std::vector + // { + // return m_queue_family_properties; + // } + +private: + vk::Gpu m_gpu; + + vk::Gpu::Properties m_properties {}; + + // VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features; + + vk::Gpu::MemoryProperties m_memory_properties {}; + + std::vector m_queue_family_properties; +}; + +} // namespace lt::renderer::vkb + + +module :private; +using namespace lt::renderer::vkb; + +Gpu::Gpu(IInstance *instance) +{ + auto gpus = vk::Gpu::enumerate(static_cast(instance)->vk()); + + for (auto &gpu : gpus) + { + auto properties = gpu.get_properties(); + auto features = gpu.get_features(); + + if (properties.device_type == vk::Gpu::Type::discrete_gpu && features.geometry_shader) + { + m_gpu = gpu; + } + } + + debug::ensure(m_gpu, "Failed to find any suitable Vulkan physical device"); + + m_memory_properties = m_gpu.get_memory_properties(); + m_queue_family_properties = m_gpu.get_queue_family_properties(); +} + +// [[nodiscard]] auto Gpu::queue_family_supports_presentation( +// VkSurfaceKHR surface, +// uint32_t queue_family_idx +// ) -> bool +// { +// auto supported = VkBool32 { false }; +// vkc(vk_get_physical_device_surface_support(m_gpu, queue_family_idx, surface, &supported)); +// +// return supported; +// } +// +// [[nodiscard]] auto Gpu::get_surface_capabilities(VkSurfaceKHR surface) const +// -> VkSurfaceCapabilitiesKHR +// { +// auto capabilities = VkSurfaceCapabilitiesKHR {}; +// vkc(vk_get_physical_device_surface_capabilities(m_gpu, surface, &capabilities)); +// return capabilities; +// } +// +// [[nodiscard]] auto Gpu::get_surface_formats(VkSurfaceKHR surface) const +// -> std::vector +// { +// auto count = uint32_t { 0u }; +// vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, nullptr)); +// +// auto formats = std::vector(count); +// vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, formats.data())); +// +// return formats; +// } + +// [[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice +// { +// auto *device = VkDevice {}; +// vkc(vk_create_device(m_gpu, &info, nullptr, &device)); +// return device; +// } diff --git a/modules/renderer/backends/vk/context/instance.cppm b/modules/renderer/backends/vk/context/instance.cppm new file mode 100644 index 0000000..c858231 --- /dev/null +++ b/modules/renderer/backends/vk/context/instance.cppm @@ -0,0 +1,149 @@ +export module renderer.backend.vk.instance; +import debug.assertions; +import renderer.frontend.instance; +import renderer.backend.vk.library_wrapper; +// import renderer.backend.vk.library_loader; +import std; + +namespace lt::renderer::vkb { + +/** + * Responsible for dynamically loading Vulkan library/functions. + * + * @note: The delayed vkInstance destruction is due to a work-around for a libx11 quirk: + * @ref: + * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/commit/0017308648b6bf8eef10ef0ffb9470576c0c2e9e + * https://www.xfree86.org/4.7.0/DRI11.html + * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1894 + */ +export class Instance: public IInstance +{ +public: + static auto get() -> IInstance * + { + return &Instance::instance(); + } + + [[nodiscard]] auto vk() -> vk::Instance & + { + return m_instance; + } + + // /* create functions */ + // [[nodiscard]] auto create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> + // VkSurfaceKHR; + // + // [[nodiscard]] auto create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const + // -> VkDebugUtilsMessengerEXT; + // + // /* destroy functions */ + // void destroy_surface(VkSurfaceKHR surface) const; + // + // void destroy_messenger(VkDebugUtilsMessengerEXT messenger) const; + // + // [[nodiscard]] auto enumerate_gpus() const -> std::vector; + +private: + static auto instance() -> IInstance & + { + static auto instance = Instance {}; + return instance; + } + + Instance(); + + vk::Instance m_instance; +}; + +} // namespace lt::renderer::vkb + +module :private; +using namespace lt::renderer::vkb; + +Instance::Instance() +{ + vk::load_library(); + vk::load_global_functions(); + + const auto app_info = vk::ApplicationInfo { + .name = "Hallo Hallo Hallo :3", + .version = vk::constants::application_version, + .engine_name = vk::constants::engine_name, + .engine_version = vk::constants::engine_version, + .api_version = vk::constants::api_version, + }; + + using Setting = vk::Instance::Layer::Setting; + const auto validation_layer_settings = std::vector { + Setting { .name = "validate_core", .values = true }, + Setting { .name = "validate_sync", .values = true }, + Setting { .name = "thread_safety", .values = true }, + Setting { .name = "debug_action", .values = true }, + Setting { .name = "enable_message_limit", .values = true }, + Setting { + .name = "duplicate_message_limit", + .values = std::numeric_limits::max(), + }, + Setting { + .name = "report_flags", + .values = std::vector { "info", "warn", "perf", "error", "verbose" }, + }, + }; + + + using Layer = vk::Instance::Layer; + m_instance = vk::Instance( + vk::Instance::CreateInfo { + .application_info = app_info, + .layers = std::vector { Layer { + .name = vk::instance_layer_names::validation, + .settings = validation_layer_settings, + } }, + .extensions = { + vk::instance_extension_names::debug_utils, + vk::instance_extension_names::surface, + vk::instance_extension_names::xlib_surface, + vk::instance_extension_names::physical_device_properties_2, + }, + } + ); + + m_instance.load_functions(); +} + +// auto Instance::enumerate_gpus() const -> std::vector +// { +// auto count = 0u; +// vkc(vk_enumerate_physical_devices(m_instance, &count, nullptr)); +// debug::ensure(count != 0u, "Failed to find any gpus with Vulkan support"); +// +// auto gpus = std::vector(count); +// vkc(vk_enumerate_physical_devices(m_instance, &count, gpus.data())); +// return gpus; +// } +// +// auto Instance::create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR +// { +// auto *value = VkSurfaceKHR {}; +// vk_create_xlib_surface_khr(m_instance, &info, m_allocator, &value); +// +// return value; +// } +// +// [[nodiscard]] auto Instance::create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const +// -> VkDebugUtilsMessengerEXT +// { +// auto *messenger = VkDebugUtilsMessengerEXT {}; +// vkc(vk_create_debug_messenger(m_instance, &info, m_allocator, &messenger)); +// return messenger; +// } +// +// void Instance::destroy_surface(VkSurfaceKHR surface) const +// { +// vk_destroy_surface_khr(m_instance, surface, m_allocator); +// } +// +// void Instance::destroy_messenger(VkDebugUtilsMessengerEXT messenger) const +// { +// vk_destroy_debug_messenger(m_instance, messenger, m_allocator); +// } diff --git a/modules/renderer/private/backend/vk/context/instance.test.cpp b/modules/renderer/backends/vk/context/instance.test.cpp similarity index 100% rename from modules/renderer/private/backend/vk/context/instance.test.cpp rename to modules/renderer/backends/vk/context/instance.test.cpp diff --git a/modules/renderer/backends/vk/context/surface.cppm b/modules/renderer/backends/vk/context/surface.cppm new file mode 100644 index 0000000..d39e285 --- /dev/null +++ b/modules/renderer/backends/vk/context/surface.cppm @@ -0,0 +1,64 @@ +export module renderer.backend.vk.surface; +import debug.assertions; +import ecs.entity; +import ecs.registry; +import memory.null_on_move; +import math.vec2; +import surface.system; +import renderer.frontend.instance; +import renderer.backend.vk.instance; +import renderer.frontend.surface; +import renderer.backend.vk.library_wrapper; + +namespace lt::renderer::vkb { + +export class Surface: public ISurface +{ +public: + Surface(IInstance *instance, const ecs::Entity &surface_entity); + + [[nodiscard]] auto vk() -> vk::Surface & + { + return m_surface; + } + + [[nodiscard]] auto get_framebuffer_size() const -> math::uvec2 override; + +private: + vk::Surface m_surface; + + ecs::Entity m_surface_entity; +}; + +} // namespace lt::renderer::vkb + +module :private; +using namespace lt::renderer::vkb; + +Surface::Surface(IInstance *instance, const ecs::Entity &surface_entity) + : m_surface_entity(surface_entity) +{ + const auto &component = surface_entity.get(); + + debug::ensure( + component.get_native_data().display, + "Failed to initialize vk::Surface: null x-display" + ); + debug::ensure( + component.get_native_data().window, + "Failed to initialize vk::Surface: null x-window" + ); + + m_surface = vk::Surface( + static_cast(instance)->vk(), + vk::Surface::XlibCreateInfo { + .display = component.get_native_data().display, + .window = component.get_native_data().window, + } + ); +} + +[[nodiscard]] auto Surface::get_framebuffer_size() const -> math::uvec2 +{ + return m_surface_entity.get().get_resolution(); +} diff --git a/modules/renderer/private/backend/vk/context/swapchain.cpp b/modules/renderer/backends/vk/context/swapchain.cppm similarity index 71% rename from modules/renderer/private/backend/vk/context/swapchain.cpp rename to modules/renderer/backends/vk/context/swapchain.cppm index 49dc5d1..1626333 100644 --- a/modules/renderer/private/backend/vk/context/swapchain.cpp +++ b/modules/renderer/backends/vk/context/swapchain.cppm @@ -1,3 +1,93 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace lt::renderer::vk { + +class Swapchain: public ISwapchain +{ +public: + Swapchain(ISurface *surface, IGpu *gpu, IDevice *device); + ~Swapchain() override; + + Swapchain(Swapchain &&) = default; + + Swapchain(const Swapchain &) = delete; + + auto operator=(Swapchain &&) -> Swapchain & = default; + + auto operator=(const Swapchain &) const -> Swapchain & = delete; + + [[nodiscard]] auto vk() const -> VkSwapchainKHR + { + return m_swapchain; + } + + [[nodiscard]] auto vk_ptr() -> VkSwapchainKHR * + { + return &m_swapchain; + } + + [[nodiscard]] auto get_resolution() const -> VkExtent2D + { + return m_resolution; + } + + [[nodiscard]] auto get_format() const -> VkFormat + { + return m_format; + } + + [[nodiscard]] auto get_image_count() const -> size_t + { + return m_images.size(); + } + + [[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView + { + return m_image_views[idx]; + } + + [[nodiscard]] auto get_image(uint32_t idx) -> VkImage + { + return m_images[idx]; + } + + + [[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const + -> std::vector; + +private: + [[nodiscard]] auto get_optimal_image_count( + VkSurfaceCapabilitiesKHR capabilities, + uint32_t desired_image_count + ) const -> uint32_t; + + memory::NullOnMove m_surface {}; + + class Gpu *m_gpu {}; + + class Device *m_device {}; + + VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; + + std::vector m_images; + + std::vector m_image_views; + + VkExtent2D m_resolution {}; + + VkFormat m_format {}; +}; + +} // namespace lt::renderer::vk + #include #include #include diff --git a/modules/renderer/private/backend/vk/data/buffer.cpp b/modules/renderer/backends/vk/data/buffer.cppm similarity index 66% rename from modules/renderer/private/backend/vk/data/buffer.cpp rename to modules/renderer/backends/vk/data/buffer.cppm index 513efd9..d771cec 100644 --- a/modules/renderer/private/backend/vk/data/buffer.cpp +++ b/modules/renderer/backends/vk/data/buffer.cppm @@ -1,3 +1,65 @@ +#pragma once + +#include +#include + +namespace lt::renderer::vk { + +class Buffer: public IBuffer +{ +public: + Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info); + + [[nodiscard]] auto map() -> std::span override; + + void unmap() override; + + // TODO(Light): this is to make copying possible. + // But it should be removed in the future, + // Right now it's not possible because: buffers can't understand CommandBuffers. + // And I'm not sure how to properly abstract over command buffers, + // before using other APIs... + [[nodiscard]] auto vk() + { + return *m_buffer; + } + + [[nodiscard]] auto get_size() const -> size_t override + { + return m_size; + } + +private: + [[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo; + + [[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags; + + [[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags; + + + [[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const + -> bool; + + [[nodiscard]] auto has_required_memory_properties( + uint32_t required_properties, + uint32_t property_flags + ) const -> bool; + + Device *m_device {}; + + Gpu *m_gpu {}; + + raii::Buffer m_buffer; + + raii::Memory m_memory; + + // TODO(Light): should this reflect the allocation size instead? + size_t m_size {}; +}; + +} // namespace lt::renderer::vk + + #include #include #include diff --git a/modules/renderer/private/backend/vk/data/descriptors.hpp b/modules/renderer/backends/vk/data/descriptors.cppm similarity index 100% rename from modules/renderer/private/backend/vk/data/descriptors.hpp rename to modules/renderer/backends/vk/data/descriptors.cppm diff --git a/modules/renderer/backends/vk/library_wrapper.cppm b/modules/renderer/backends/vk/library_wrapper.cppm new file mode 100644 index 0000000..1ec4fcd --- /dev/null +++ b/modules/renderer/backends/vk/library_wrapper.cppm @@ -0,0 +1,951 @@ +module; +#define VK_NO_PROTOTYPES +#define VK_USE_PLATFORM_XLIB_KHR +#include +#include +#include + +#if defined(_WIN32) + #error "Unsupported platform" +#elif defined(__unix__) + #include +#endif + +export module renderer.backend.vk.library_wrapper; +import memory.null_on_move; +import math.vec3; +import debug.assertions; +import std; + +template +struct overloads: Ts... +{ + using Ts::operator()...; +}; + +export namespace lt::renderer::vk { + +using Bool32 = VkBool32; + +namespace constants { + +constexpr auto application_version = VK_MAKE_VERSION(1, 0, 0); +constexpr auto engine_version = VK_MAKE_VERSION(1, 0, 0); +constexpr auto api_version = VK_API_VERSION_1_4; +constexpr auto engine_name = std::string_view { "light_engine_vulkan_renderer" }; + +constexpr auto max_physical_device_name = VK_MAX_PHYSICAL_DEVICE_NAME_SIZE; +constexpr auto max_memory_types = VK_MAX_MEMORY_TYPES; +constexpr auto max_memory_heaps = VK_MAX_MEMORY_HEAPS; +constexpr auto uuid_size = VK_UUID_SIZE; + +} // namespace constants + + +namespace instance_layer_names { + +constexpr auto validation = "VK_LAYER_KHRONOS_validation"; + +} + +namespace instance_extension_names { + +constexpr auto debug_utils = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; +constexpr auto surface = VK_KHR_SURFACE_EXTENSION_NAME; +constexpr auto xlib_surface = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; +constexpr auto physical_device_properties_2 + = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; + +} // namespace instance_extension_names + +namespace device_extension_names { + +constexpr auto xlib_surface = VK_KHR_XLIB_SURFACE_EXTENSION_NAME; +constexpr auto swapchain = VK_KHR_SWAPCHAIN_EXTENSION_NAME; +constexpr auto dynamic_rendering = VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME; +constexpr auto descriptor_indexing = VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME; + +}; // namespace device_extension_names + + +void load_library(); + +void unload_library(); + +void load_global_functions(); + +void load_device_functions(VkDevice device); + +using Version_T = uint32_t; + +struct ApplicationInfo +{ + std::string_view name; + + Version_T version; + + std::string_view engine_name; + + Version_T engine_version; + + Version_T api_version; +}; + +namespace QueueFlags { +enum T : std::underlying_type_t // NOLINT +{ + graphics_bit = VK_QUEUE_GRAPHICS_BIT, + compute_bit = VK_QUEUE_COMPUTE_BIT, + transfer_bit = VK_QUEUE_TRANSFER_BIT, + sparse_binding_bit = VK_QUEUE_SPARSE_BINDING_BIT, + protected_bit = VK_QUEUE_PROTECTED_BIT, + video_decode_bit_khr = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + video_encode_bit_khr = VK_QUEUE_VIDEO_ENCODE_BIT_KHR, + optical_flow_bit_nv = VK_QUEUE_OPTICAL_FLOW_BIT_NV, +}; +} + +namespace MemoryHeapFlags { +enum T : std::underlying_type_t // NOLINT +{ + + device_local_bit = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + multi_instance_bit = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT, + tile_memory_bit = VK_MEMORY_HEAP_TILE_MEMORY_BIT_QCOM, +}; +}; + +namespace MemoryPropertyFlags { +enum T : std::underlying_type_t // NOLINT +{ + + device_local_bit = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + host_visible_bit = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + host_coherent_bit = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + host_cached_bit = VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + lazily_allocated_bit = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, + protected_bit = VK_MEMORY_PROPERTY_PROTECTED_BIT, + device_coherent_bit_amd = VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD, + device_uncached_bit_amd = VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD, + rdma_capable_bit_nv = VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV, +}; +} + +class Instance +{ +public: + friend class Surface; + friend class Gpu; + + struct Layer + { + struct Setting + { + std::string name; + std::variant, std::uint32_t, bool> values; + }; + + std::string name; + + std::vector settings; + }; + + using Extension = std::string; + + struct CreateInfo + { + ApplicationInfo application_info; + + std::vector layers; + + std::vector extensions; + }; + + Instance() = default; + + Instance(CreateInfo info); + + Instance(Instance &&) = default; + + Instance(const Instance &) = delete; + + auto operator=(Instance &&) -> Instance & = default; + + auto operator=(const Instance &) = delete; + + ~Instance(); + + void load_functions(); + + [[nodiscard]] operator bool() const + { + return m_instance != VK_NULL_HANDLE; + } + +private: + memory::NullOnMove m_instance {}; +}; + +class Surface +{ +public: + friend class Gpu; + + struct XlibCreateInfo + { + Display *display; + + Window window; + }; + + Surface() = default; + + Surface(const Instance &instance, const XlibCreateInfo &info); + + Surface(Surface &&) = default; + + Surface(const Surface &) = delete; + + auto operator=(Surface &&) -> Surface & = default; + + auto operator=(const Surface &) -> Surface & = delete; + + ~Surface(); + + [[nodiscard]] operator bool() const + { + return m_surface != VK_NULL_HANDLE; + } + +private: + memory::NullOnMove m_surface {}; + + VkInstance m_instance {}; +}; + +class Gpu +{ +public: + enum class Type : uint8_t + { + other = 0, + integrated_gpu = 1, + discrete_gpu = 2, + virtual_gpu = 3, + cpu = 4, + }; + + struct Features + { + Bool32 robust_buffer_access; + Bool32 full_draw_index_uint32; + Bool32 image_cube_array; + Bool32 independent_blend; + Bool32 geometry_shader; + Bool32 tessellation_shader; + Bool32 sample_rate_shading; + Bool32 dual_src_blend; + Bool32 logic_op; + Bool32 multi_draw_indirect; + Bool32 draw_indirect_first_instance; + Bool32 depth_clamp; + Bool32 depth_bias_clamp; + Bool32 fill_mode_non_solid; + Bool32 depth_bounds; + Bool32 wide_lines; + Bool32 large_points; + Bool32 alpha_to_one; + Bool32 multi_viewport; + Bool32 sampler_anisotropy; + Bool32 texture_compression_etc2; + Bool32 texture_compression_astc_ldr; + Bool32 texture_compression_bc; + Bool32 occlusion_query_precise; + Bool32 pipeline_statistics_query; + Bool32 vertex_pipeline_stores_and_atomics; + Bool32 fragment_stores_and_atomics; + Bool32 shader_tessellation_and_geometry_point_size; + Bool32 shader_image_gather_extended; + Bool32 shader_storage_image_extended_formats; + Bool32 shader_storage_image_multisample; + Bool32 shader_storage_image_read_without_format; + Bool32 shader_storage_image_write_without_format; + Bool32 shader_uniform_buffer_array_dynamic_indexing; + Bool32 shader_sampled_image_array_dynamic_indexing; + Bool32 shader_storage_buffer_array_dynamic_indexing; + Bool32 shader_storage_image_array_dynamic_indexing; + Bool32 shader_clip_distance; + Bool32 shader_cull_distance; + Bool32 shader_float64; + Bool32 shader_int64; + Bool32 shader_int16; + Bool32 shader_resource_residency; + Bool32 shader_resource_min_lod; + Bool32 sparse_binding; + Bool32 sparse_residency_buffer; + Bool32 sparse_residency_image_2d; + Bool32 sparse_residency_image_3d; + Bool32 sparse_residency_2_samples; + Bool32 sparse_residency_4_samples; + Bool32 sparse_residency_8_samples; + Bool32 sparse_residency_16_samples; + Bool32 sparse_residency_aliased; + Bool32 variable_multisample_rate; + Bool32 inherited_queries; + }; + + struct Limits + { + std::uint32_t max_image_dimension_1d; + std::uint32_t max_image_dimension_2d; + std::uint32_t max_image_dimension_3d; + std::uint32_t max_image_dimension_cube; + std::uint32_t max_image_array_layers; + std::uint32_t max_texel_buffer_elements; + std::uint32_t max_uniform_buffer_range; + std::uint32_t max_storage_buffer_range; + std::uint32_t max_push_constants_size; + std::uint32_t max_memory_allocation_count; + std::uint32_t max_sampler_allocation_count; + std::size_t buffer_image_granularity; + std::size_t sparse_address_space_size; + std::uint32_t max_bound_descriptor_sets; + std::uint32_t max_per_stage_descriptor_samplers; + std::uint32_t max_per_stage_descriptor_uniform_buffers; + std::uint32_t max_per_stage_descriptor_storage_buffers; + std::uint32_t max_per_stage_descriptor_sampled_images; + std::uint32_t max_per_stage_descriptor_storage_images; + std::uint32_t max_per_stage_descriptor_input_attachments; + std::uint32_t max_per_stage_resources; + std::uint32_t max_descriptor_set_samplers; + std::uint32_t max_descriptor_set_uniform_buffers; + std::uint32_t max_descriptor_set_uniform_buffers_dynamic; + std::uint32_t max_descriptor_set_storage_buffers; + std::uint32_t max_descriptor_set_storage_buffers_dynamic; + std::uint32_t max_descriptor_set_sampled_images; + std::uint32_t max_descriptor_set_storage_images; + std::uint32_t max_descriptor_set_input_attachments; + std::uint32_t max_vertex_input_attributes; + std::uint32_t max_vertex_input_bindings; + std::uint32_t max_vertex_input_attribute_offset; + std::uint32_t max_vertex_input_binding_stride; + std::uint32_t max_vertex_output_components; + std::uint32_t max_tessellation_generation_level; + std::uint32_t max_tessellation_patch_size; + std::uint32_t max_tessellation_control_per_vertex_input_components; + std::uint32_t max_tessellation_control_per_vertex_output_components; + std::uint32_t max_tessellation_control_per_patch_output_components; + std::uint32_t max_tessellation_control_total_output_components; + std::uint32_t max_tessellation_evaluation_input_components; + std::uint32_t max_tessellation_evaluation_output_components; + std::uint32_t max_geometry_shader_invocations; + std::uint32_t max_geometry_input_components; + std::uint32_t max_geometry_output_components; + std::uint32_t max_geometry_output_vertices; + std::uint32_t max_geometry_total_output_components; + std::uint32_t max_fragment_input_components; + std::uint32_t max_fragment_output_attachments; + std::uint32_t max_fragment_dual_src_attachments; + std::uint32_t max_fragment_combined_output_resources; + std::uint32_t max_compute_shared_memory_size; + std::array max_compute_work_group_count; + std::uint32_t max_compute_work_group_invocations; + std::array max_compute_work_group_size; + std::uint32_t sub_pixel_precision_bits; + std::uint32_t sub_texel_precision_bits; + std::uint32_t mipmap_precision_bits; + std::uint32_t max_draw_indexed_index_value; + std::uint32_t max_draw_indirect_count; + float max_sampler_lod_bias; + float max_sampler_anisotropy; + std::uint32_t max_viewports; + std::array max_viewport_dimensions; + std::array viewport_bounds_range; + std::uint32_t viewport_sub_pixel_bits; + std::size_t min_memory_map_alignment; + VkDeviceSize min_texel_buffer_offset_alignment; + VkDeviceSize min_uniform_buffer_offset_alignment; + VkDeviceSize min_storage_buffer_offset_alignment; + std::int32_t min_texel_offset; + std::uint32_t max_texel_offset; + std::int32_t min_texel_gather_offset; + std::uint32_t max_texel_gather_offset; + float min_interpolation_offset; + float max_interpolation_offset; + std::uint32_t sub_pixel_interpolation_offset_bits; + std::uint32_t max_framebuffer_width; + std::uint32_t max_framebuffer_height; + std::uint32_t max_framebuffer_layers; + VkSampleCountFlags framebuffer_color_sample_counts; + VkSampleCountFlags framebuffer_depth_sample_counts; + VkSampleCountFlags framebuffer_stencil_sample_counts; + VkSampleCountFlags framebuffer_no_attachments_sample_counts; + std::uint32_t max_color_attachments; + VkSampleCountFlags sampled_image_color_sample_counts; + VkSampleCountFlags sampled_image_integer_sample_counts; + VkSampleCountFlags sampled_image_depth_sample_counts; + VkSampleCountFlags sampled_image_stencil_sample_counts; + VkSampleCountFlags storage_image_sample_counts; + std::uint32_t max_sample_mask_words; + Bool32 timestamp_compute_and_graphics; + float timestamp_period; + std::uint32_t max_clip_distances; + std::uint32_t max_cull_distances; + std::uint32_t max_combined_clip_and_cull_distances; + std::uint32_t discrete_queue_priorities; + std::array point_size_range; + std::array line_width_range; + float point_size_granularity; + float line_width_granularity; + Bool32 strict_lines; + Bool32 standard_sample_locations; + std::size_t optimal_buffer_copy_offset_alignment; + std::size_t optimal_buffer_copy_row_pitch_alignment; + std::size_t non_coherent_atom_size; + }; + + struct SparseProperties + { + Bool32 residency_standard_2d_block_shape; + Bool32 residency_standard_2d_multisample_block_shape; + Bool32 residency_standard_3d_block_shape; + Bool32 residency_aligned_mip_size; + Bool32 residency_non_resident_strict; + }; + + struct Properties + { + std::uint32_t api_version; + std::uint32_t driver_version; + std::uint32_t vendor_id; + std::uint32_t device_id; + Type device_type; + std::array device_name; + std::array pipeline_cache_uuid; + Limits limits; + SparseProperties sparse_properties; + }; + + struct MemoryType + { + MemoryPropertyFlags::T property_flags; + std::uint32_t heap_idx; + }; + + struct MemoryHeap + { + std::size_t size; + MemoryHeapFlags::T flags; + }; + + struct MemoryProperties + { + std::uint32_t memory_type_count; + std::array memory_types; + + std::uint32_t memory_heap_count; + std::array memory_heaps; + }; + + struct QueueFamilyProperties + { + QueueFlags::T queue_flags {}; + std::uint32_t queue_count {}; + std::uint32_t timestamp_valid_bits {}; + math::uvec3 min_image_transfer_granularity; + }; + + [[nodiscard]] + static auto enumerate(const Instance &instance) -> std::vector; + + Gpu() = default; + + Gpu(Gpu &&) = default; + + Gpu(const Gpu &) = default; + + auto operator=(Gpu &&) -> Gpu & = default; + + auto operator=(const Gpu &) -> Gpu & = default; + + ~Gpu(); + + [[nodiscard]] auto get_properties() const -> Properties; + + [[nodiscard]] auto get_features() const -> Features; + + [[nodiscard]] auto get_memory_properties() const -> MemoryProperties; + + [[nodiscard]] auto get_queue_family_properties() const -> std::vector; + + [[nodiscard]] auto queue_family_supports_surface( + const Surface &surface, + std::uint32_t queue_family_idx + ) const -> bool; + + [[nodiscard]] operator bool() const + { + return m_physical_device != VK_NULL_HANDLE; + } + +private: + VkPhysicalDevice m_physical_device {}; + + VkInstance m_instance {}; +}; + +class Device +{ +public: + struct CreateInfo + { + std::set queue_indices; + + std::vector extensions; + + Gpu::Features required_gpu_features; + }; + + Device() = default; + + Device(CreateInfo info); + + Device(Device &&) = default; + + Device(const Device &) = delete; + + auto operator=(Device &&) -> Device & = default; + + auto operator=(const Device &) -> Device & = delete; + + ~Device(); + +private: + memory::NullOnMove m_device {}; +}; + +[[nodiscard]] +auto enumerate_instance_extension_properties() -> std::vector; + + +} // namespace lt::renderer::vk + +module :private; +using namespace lt::renderer::vk; + +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) +// global functions +PFN_vkGetInstanceProcAddr vk_get_instance_proc_address {}; +PFN_vkCreateInstance vk_create_instance {}; +PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties {}; +PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties {}; + +// instance functions +PFN_vkDestroyInstance vk_destroy_instance {}; +PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices {}; + +PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties {}; +PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties {}; +PFN_vkCreateDevice vk_create_device {}; +PFN_vkGetDeviceProcAddr vk_get_device_proc_address {}; +PFN_vkDestroyDevice vk_destroy_device {}; +PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {}; +PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {}; +PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {}; + +// extension instance functions +PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {}; +PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label {}; +PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label {}; +PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger {}; +PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger {}; +PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label {}; +PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label {}; +PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label {}; +PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name {}; +PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag {}; +PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message {}; + +// surface instance functions +PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {}; +PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {}; +PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {}; + +// device functions +PFN_vkGetDeviceQueue vk_get_device_queue {}; +PFN_vkCreateCommandPool vk_create_command_pool {}; +PFN_vkDestroyCommandPool vk_destroy_command_pool {}; +PFN_vkAllocateCommandBuffers vk_allocate_command_buffers {}; +PFN_vkFreeCommandBuffers vk_free_command_buffers {}; +PFN_vkBeginCommandBuffer vk_begin_command_buffer {}; +PFN_vkEndCommandBuffer vk_end_command_buffer {}; +PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier {}; +PFN_vkQueueSubmit vk_queue_submit {}; +PFN_vkQueueWaitIdle vk_queue_wait_idle {}; +PFN_vkDeviceWaitIdle vk_device_wait_idle {}; +PFN_vkCreateFence vk_create_fence {}; +PFN_vkDestroyFence vk_destroy_fence {}; +PFN_vkWaitForFences vk_wait_for_fences {}; +PFN_vkResetFences vk_reset_fences {}; +PFN_vkCreateSemaphore vk_create_semaphore {}; +PFN_vkDestroySemaphore vk_destroy_semaphore {}; +PFN_vkCreateSwapchainKHR vk_create_swapchain_khr {}; +PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr {}; +PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr {}; +PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr {}; +PFN_vkQueuePresentKHR vk_queue_present_khr {}; +PFN_vkCreateImageView vk_create_image_view {}; +PFN_vkDestroyImageView vk_destroy_image_view {}; +PFN_vkCreateRenderPass vk_create_render_pass {}; +PFN_vkDestroyRenderPass vk_destroy_render_pass {}; +PFN_vkCreateFramebuffer vk_create_frame_buffer {}; +PFN_vkDestroyFramebuffer vk_destroy_frame_buffer {}; +PFN_vkCreateShaderModule vk_create_shader_module {}; +PFN_vkDestroyShaderModule vk_destroy_shader_module {}; +PFN_vkCreatePipelineLayout vk_create_pipeline_layout {}; +PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout {}; +PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines {}; +PFN_vkDestroyPipeline vk_destroy_pipeline {}; +PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass {}; +PFN_vkCmdEndRenderPass vk_cmd_end_render_pass {}; +PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {}; +PFN_vkCmdDraw vk_cmd_draw {}; +PFN_vkCmdSetViewport vk_cmd_set_viewport {}; +PFN_vkCmdSetScissor vk_cmd_set_scissors {}; +PFN_vkCmdPushConstants vk_cmd_push_constants {}; +PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {}; + +PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {}; +PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {}; +PFN_vkCreateDescriptorPool vk_create_descriptor_pool {}; +PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {}; +PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {}; +PFN_vkFreeDescriptorSets vk_free_descriptor_sets {}; + +PFN_vkCreateBuffer vk_create_buffer {}; +PFN_vkDestroyBuffer vk_destroy_buffer {}; +PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {}; +PFN_vkAllocateMemory vk_allocate_memory {}; +PFN_vkBindBufferMemory vk_bind_buffer_memory {}; +PFN_vkMapMemory vk_map_memory {}; +PFN_vkUnmapMemory vk_unmap_memory {}; +PFN_vkFreeMemory vk_free_memory {}; + +PFN_vkResetCommandBuffer vk_reset_command_buffer {}; + +PFN_vkCmdBeginRendering vk_cmd_begin_rendering {}; +PFN_vkCmdEndRendering vk_cmd_end_rendering {}; + +PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr {}; +PFN_vkDestroySurfaceKHR vk_destroy_surface_khr {}; +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + +namespace { +void *library = nullptr; // NOLINT +} + +void load_library() +{ + constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE; + library = dlopen("libvulkan.so.1", runtime_loader_flags); + if (!library) + { + library = dlopen("libvulkan.so", runtime_loader_flags); + } + lt::debug::ensure(library, "Failed to dlopen vulkan library"); + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + vk_get_instance_proc_address = reinterpret_cast( + dlsym(library, "vkGetInstanceProcAddr") + ); + lt::debug::ensure( + vk_get_instance_proc_address, + "Failed to load vulkan function: vkGetInstanceProcAddr" + ); +} + +void vkc(VkResult result) +{ + if (result) + { + throw std::runtime_error { + std::format("Vulkan call failed with result: {}", std::to_underlying(result)) + }; + } +} + +void unload_library() +{ + if (!library) + { + return; + } + + // calling dlclose causes many issues with runtime analyzers + // eg. https://github.com/google/sanitizers/issues/89 + // with no noticable gains, so we just don't bother closing it. + + // dlclose(library); + // library = nullptr; +} + +void load_global_functions() +{ + constexpr auto load_fn = [](T &pfn, const char *fn_name) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + pfn = reinterpret_cast(vk_get_instance_proc_address(nullptr, fn_name)); + lt::debug::ensure(pfn, "Failed to load vulkan global function: {}", fn_name); + // log::trace("Loaded global function: {}", fn_name); + }; + + load_fn(vk_create_instance, "vkCreateInstance"); + load_fn(vk_enumerate_instance_extension_properties, "vkEnumerateInstanceExtensionProperties"); + load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties"); +} + +void Instance::load_functions() +{ + const auto load_fn = [this](T &pfn, const char *fn_name) { + pfn = std::bit_cast(vk_get_instance_proc_address(m_instance, fn_name)); + lt::debug::ensure(pfn, "Failed to load vulkan instance function: {}", fn_name); + }; + + load_fn(vk_destroy_instance, "vkDestroyInstance"); + load_fn(vk_enumerate_physical_devices, "vkEnumeratePhysicalDevices"); + load_fn(vk_get_physical_device_properties, "vkGetPhysicalDeviceProperties"); + load_fn( + vk_get_physical_device_queue_family_properties, + "vkGetPhysicalDeviceQueueFamilyProperties" + ); + load_fn(vk_create_device, "vkCreateDevice"); + load_fn(vk_get_device_proc_address, "vkGetDeviceProcAddr"); + load_fn(vk_destroy_device, "vkDestroyDevice"); + load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures"); + load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties"); + load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties"); + + load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT"); + load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT"); + load_fn(vk_cmd_insert_debug_label, "vkCmdInsertDebugUtilsLabelEXT"); + load_fn(vk_create_debug_messenger, "vkCreateDebugUtilsMessengerEXT"); + load_fn(vk_destroy_debug_messenger, "vkDestroyDebugUtilsMessengerEXT"); + load_fn(vk_queue_begin_debug_label, "vkQueueBeginDebugUtilsLabelEXT"); + load_fn(vk_queue_end_debug_label, "vkQueueEndDebugUtilsLabelEXT"); + load_fn(vk_queue_insert_debug_label, "vkQueueInsertDebugUtilsLabelEXT"); + load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT"); + load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT"); + load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT"); + + load_fn(vk_get_physical_device_surface_support, "vkGetPhysicalDeviceSurfaceSupportKHR"); + load_fn( + vk_get_physical_device_surface_capabilities, + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" + ); + load_fn(vk_get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + load_fn(vk_create_xlib_surface_khr, "vkCreateXlibSurfaceKHR"); + load_fn(vk_destroy_surface_khr, "vkDestroySurfaceKHR"); +} + +void load_device_functions(VkDevice device) +{ + const auto load_fn = [device](T &pfn, const char *fn_name) { + pfn = std::bit_cast(vk_get_device_proc_address(device, fn_name)); + lt::debug::ensure(pfn, "Failed to load vulkan device function: {}", fn_name); + }; + + load_fn(vk_get_device_queue, "vkGetDeviceQueue"); + load_fn(vk_create_command_pool, "vkCreateCommandPool"); + load_fn(vk_destroy_command_pool, "vkDestroyCommandPool"); + load_fn(vk_allocate_command_buffers, "vkAllocateCommandBuffers"); + load_fn(vk_free_command_buffers, "vkFreeCommandBuffers"); + load_fn(vk_begin_command_buffer, "vkBeginCommandBuffer"); + load_fn(vk_end_command_buffer, "vkEndCommandBuffer"); + load_fn(vk_cmd_pipeline_barrier, "vkCmdPipelineBarrier"); + load_fn(vk_queue_submit, "vkQueueSubmit"); + load_fn(vk_queue_wait_idle, "vkQueueWaitIdle"); + load_fn(vk_device_wait_idle, "vkDeviceWaitIdle"); + load_fn(vk_create_fence, "vkCreateFence"); + load_fn(vk_destroy_fence, "vkDestroyFence"); + load_fn(vk_wait_for_fences, "vkWaitForFences"); + load_fn(vk_reset_fences, "vkResetFences"); + load_fn(vk_create_semaphore, "vkCreateSemaphore"); + load_fn(vk_destroy_semaphore, "vkDestroySemaphore"); + load_fn(vk_create_swapchain_khr, "vkCreateSwapchainKHR"); + load_fn(vk_destroy_swapchain_khr, "vkDestroySwapchainKHR"); + load_fn(vk_get_swapchain_images_khr, "vkGetSwapchainImagesKHR"); + load_fn(vk_acquire_next_image_khr, "vkAcquireNextImageKHR"); + load_fn(vk_queue_present_khr, "vkQueuePresentKHR"); + load_fn(vk_create_image_view, "vkCreateImageView"); + load_fn(vk_destroy_image_view, "vkDestroyImageView"); + load_fn(vk_create_render_pass, "vkCreateRenderPass"); + load_fn(vk_destroy_render_pass, "vkDestroyRenderPass"); + load_fn(vk_create_frame_buffer, "vkCreateFramebuffer"); + load_fn(vk_destroy_frame_buffer, "vkDestroyFramebuffer"); + load_fn(vk_create_shader_module, "vkCreateShaderModule"); + load_fn(vk_destroy_shader_module, "vkDestroyShaderModule"); + load_fn(vk_create_pipeline_layout, "vkCreatePipelineLayout"); + load_fn(vk_destroy_pipeline_layout, "vkDestroyPipelineLayout"); + load_fn(vk_create_graphics_pipelines, "vkCreateGraphicsPipelines"); + load_fn(vk_destroy_pipeline, "vkDestroyPipeline"); + load_fn(vk_cmd_begin_render_pass, "vkCmdBeginRenderPass"); + load_fn(vk_cmd_end_render_pass, "vkCmdEndRenderPass"); + load_fn(vk_cmd_bind_pipeline, "vkCmdBindPipeline"); + load_fn(vk_cmd_draw, "vkCmdDraw"); + load_fn(vk_cmd_set_viewport, "vkCmdSetViewport"); + load_fn(vk_cmd_set_scissors, "vkCmdSetScissor"); + load_fn(vk_cmd_push_constants, "vkCmdPushConstants"); + load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer"); + load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout"); + load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout"); + load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool"); + load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool"); + load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets"); + load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets"); + load_fn(vk_create_buffer, "vkCreateBuffer"); + load_fn(vk_destroy_buffer, "vkDestroyBuffer"); + load_fn(vk_allocate_memory, "vkAllocateMemory"); + load_fn(vk_bind_buffer_memory, "vkBindBufferMemory"); + load_fn(vk_map_memory, "vkMapMemory"); + load_fn(vk_unmap_memory, "vkUnmapMemory"); + load_fn(vk_free_memory, "vkFreeMemory"); + load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements"); + load_fn(vk_reset_command_buffer, "vkResetCommandBuffer"); + + load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering"); + load_fn(vk_cmd_end_rendering, "vkCmdEndRendering"); +} + +Instance::Instance(CreateInfo info) +{ + const auto layer_setting_type_visitor = overloads { + [](const std::vector &) { return VK_LAYER_SETTING_TYPE_STRING_EXT; }, + [](std::uint32_t) { return VK_LAYER_SETTING_TYPE_UINT32_EXT; }, + [](bool) { return VK_LAYER_SETTING_TYPE_BOOL32_EXT; }, + }; + + const auto layer_setting_value_visitor = overloads { + [](std::vector values) { return std::bit_cast(values.data()); }, + [](std::uint32_t value) { return std::bit_cast(&value); }, + [](bool value) { return std::bit_cast(&value); }, + }; + + auto layer_settings = std::vector {}; + auto layer_names = std::vector {}; + auto extension_names = std::vector {}; + + for (const auto &layer : info.layers) + { + layer_names.emplace_back(layer.name.c_str()); + for (const auto &setting : layer.settings) + { + layer_settings.emplace_back( + VkLayerSettingEXT { + .pLayerName = layer.name.c_str(), + .pSettingName = setting.name.c_str(), + .type = std::visit(layer_setting_type_visitor, setting.values), + .valueCount = 1u, + .pValues = std::visit(layer_setting_value_visitor, setting.values), + } + ); + } + } + + const auto layer_settings_create_info = VkLayerSettingsCreateInfoEXT { + .sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, + .settingCount = static_cast(layer_settings.size()), + .pSettings = layer_settings.data(), + }; + + auto vk_info = VkInstanceCreateInfo { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = &layer_settings_create_info, + .flags = {}, + .enabledLayerCount = static_cast(info.layers.size()), + .ppEnabledLayerNames = layer_names.data(), + .enabledExtensionCount = static_cast(info.extensions.size()), + .ppEnabledExtensionNames = extension_names.data(), + }; + + vkc(vk_create_instance(&vk_info, nullptr, &m_instance)); + debug::ensure(m_instance, "Failed to create vulkan instance"); +} + +Surface::Surface(const Instance &instance, const XlibCreateInfo &info) + : m_instance(instance.m_instance) +{ + const auto vk_info = VkXlibSurfaceCreateInfoKHR { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .pNext = {}, + .flags = {}, + .dpy = info.display, + .window = info.window, + }; + + vkc(vk_create_xlib_surface_khr(instance.m_instance, &vk_info, nullptr, &m_surface)); +} + +Surface::~Surface() +{ + vk_destroy_surface_khr(m_instance, m_surface, nullptr); +} + + +[[nodiscard]] +/* static */ auto Gpu::enumerate(const Instance &instance) -> std::vector +{ + auto count = 0u; + vkc(vk_enumerate_physical_devices(instance.m_instance, &count, nullptr)); + debug::ensure(count != 0u, "Failed to find any gpus with Vulkan support"); + + auto vk_gpus = std::vector(count); + vkc(vk_enumerate_physical_devices(instance.m_instance, &count, vk_gpus.data())); + + auto gpus = std::vector(count); + for (auto [vk_gpu, gpu] : std::views::zip(vk_gpus, gpus)) + { + gpu.m_instance = instance.m_instance; + gpu.m_physical_device = vk_gpu; + } + + return gpus; +} + +[[nodiscard]] auto Gpu::queue_family_supports_surface( + const Surface &surface, + std::uint32_t queue_family_idx +) const -> bool +{ + auto supported = VkBool32 { false }; + vkc(vk_get_physical_device_surface_support( + m_physical_device, + queue_family_idx, + surface.m_surface, + &supported + )); + return supported; +} + +Device::Device(CreateInfo info) +{ +} + +Device::~Device() +{ + if (m_device) + { + vk_destroy_device(m_device, nullptr); + } +} + +[[nodiscard]] +auto enumerate_instance_extension_properties() -> std::vector +{ + auto count = 0u; + vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr)); + + auto extensions = std::vector(count); + std::memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties)); + vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data())); + + return extensions; +} diff --git a/modules/renderer/backends/vk/library_wrapper.cppma b/modules/renderer/backends/vk/library_wrapper.cppma new file mode 100644 index 0000000..81b27b3 --- /dev/null +++ b/modules/renderer/backends/vk/library_wrapper.cppma @@ -0,0 +1,102 @@ +module; +#define VK_NO_PROTOTYPES +#define VK_USE_PLATFORM_XLIB_KHR +#include +#include +#include + +export module renderer.backend.vk.library_wrapper; +import std; +// import renderer.backend.vk.library_loader; + +namespace lt::renderer::vk { + +class Device +{ +public: + struct CreateInfo + { + std::vector queue_create_infos; + + std::vector layers; + + std::vector extensions; + + VkPhysicalDeviceFeatures2 features; + }; + + Device() = default; + + Device(CreateInfo info) + { + } + + ~Device() + { + if (m_device) + { + vk_destroy_device(m_device, nullptr); + } + } + +private: + VkDevice m_device {}; +}; + +}; // namespace lt::renderer::vk + +export namespace lt::renderer::vk { + +using Version_T = uint32_t; + +struct ApplicationInfo +{ + std::string_view name; + + Version_T version; + + std::string_view *engine_name; + + Version_T engine_version; + + Version_T api_version; +}; + +[[nodiscard]] +auto enumerate_instance_extension_properties() -> std::vector +{ + auto count = 0u; + vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr)); + + auto extensions = std::vector(count); + std::memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties)); + vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data())); + + return extensions; +} + +struct VkInstanceCreateInfo +{ + VkInstanceCreateFlags flags; + + ApplicationInfo application_info; + + std::vector layers; + + std::vector extensions; + + const void *next; +}; + +class Instance +{ +}; + +[[nodiscard]] auto create_instance() -> VkInstance +{ + return VkInstanceCreateInfo + { + } +} + +} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/messenger.cpp b/modules/renderer/backends/vk/messenger.cppm similarity index 76% rename from modules/renderer/private/backend/vk/messenger.cpp rename to modules/renderer/backends/vk/messenger.cppm index bc0d711..8506930 100644 --- a/modules/renderer/private/backend/vk/messenger.cpp +++ b/modules/renderer/backends/vk/messenger.cppm @@ -1,8 +1,58 @@ -#include -#include +export module renderer.backends.vk.messenger; + +import memory.null_on_move; +import renderer.backends.vk.instance; +import renderer.backends.vk.raii; +import renderer.backends.vk.library; +import std; + namespace lt::renderer::vk { +class Messenger: public IMessenger +{ +public: + Messenger(IInstance *instance, CreateInfo info); + +private: + static auto native_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT *callback_data, + void *vulkan_user_data + ) -> VkBool32; + + [[nodiscard]] static auto to_native_severity(MessageSeverity severity) + -> VkDebugUtilsMessageSeverityFlagsEXT; + + [[nodiscard]] static auto from_native_severity(VkDebugUtilsMessageSeverityFlagsEXT severity) + -> MessageSeverity; + + [[nodiscard]] static auto to_native_type(MessageType type) -> VkDebugUtilsMessageTypeFlagsEXT; + + [[nodiscard]] static auto from_native_type(VkDebugUtilsMessageTypeFlagsEXT type) -> MessageType; + + class Instance *m_instance {}; + + raii::DebugMessenger m_debug_messenger; + + MessageSeverity m_severities {}; + + MessageType m_types {}; + + Callback_T m_user_callback; + + std::any m_user_data; +}; + +} // namespace lt::renderer::vk + + +module :private; +using namespace lt::renderer::vk; + +import logger; + Messenger::Messenger(IInstance *instance, CreateInfo info) : m_instance(static_cast(instance)) , m_user_data(std::move(info.user_data)) @@ -162,5 +212,3 @@ Messenger::Messenger(IInstance *instance, CreateInfo info) return static_cast(flags); } - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/messenger.test.cpp b/modules/renderer/backends/vk/messenger.test.cpp similarity index 100% rename from modules/renderer/private/backend/vk/messenger.test.cpp rename to modules/renderer/backends/vk/messenger.test.cpp diff --git a/modules/renderer/private/backend/vk/raii/raii.hpp b/modules/renderer/backends/vk/raii.cppm similarity index 98% rename from modules/renderer/private/backend/vk/raii/raii.hpp rename to modules/renderer/backends/vk/raii.cppm index 7e4ea9a..48939b7 100644 --- a/modules/renderer/private/backend/vk/raii/raii.hpp +++ b/modules/renderer/backends/vk/raii.cppm @@ -4,7 +4,7 @@ #include -namespace lt::renderer::vk::raii { +export namespace lt::renderer::vk::raii { class DebugMessenger { diff --git a/modules/renderer/private/backend/vk/renderer/pass.cpp b/modules/renderer/backends/vk/renderer/pass.cpp similarity index 100% rename from modules/renderer/private/backend/vk/renderer/pass.cpp rename to modules/renderer/backends/vk/renderer/pass.cpp diff --git a/modules/renderer/private/backend/vk/renderer/pass.hpp b/modules/renderer/backends/vk/renderer/pass.cppm similarity index 100% rename from modules/renderer/private/backend/vk/renderer/pass.hpp rename to modules/renderer/backends/vk/renderer/pass.cppm diff --git a/modules/renderer/private/backend/vk/renderer/renderer.cpp b/modules/renderer/backends/vk/renderer/renderer.cpp similarity index 100% rename from modules/renderer/private/backend/vk/renderer/renderer.cpp rename to modules/renderer/backends/vk/renderer/renderer.cpp diff --git a/modules/renderer/private/backend/vk/renderer/renderer.hpp b/modules/renderer/backends/vk/renderer/renderer.cppm similarity index 100% rename from modules/renderer/private/backend/vk/renderer/renderer.hpp rename to modules/renderer/backends/vk/renderer/renderer.cppm diff --git a/modules/renderer/backends/vk/utils.cppm b/modules/renderer/backends/vk/utils.cppm new file mode 100644 index 0000000..dc7b93c --- /dev/null +++ b/modules/renderer/backends/vk/utils.cppm @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace lt::renderer::vk { + + +} // namespace lt::renderer::vk diff --git a/modules/renderer/public/components/sprite.hpp b/modules/renderer/components.cppm similarity index 67% rename from modules/renderer/public/components/sprite.hpp rename to modules/renderer/components.cppm index e4448e3..a1fe2d9 100644 --- a/modules/renderer/public/components/sprite.hpp +++ b/modules/renderer/components.cppm @@ -1,45 +1,43 @@ -#pragma once - -#include -#include -#include +export module renderer.components; +import assets.shader; +import math.vec3; +import memory.reference; +import std; namespace lt::renderer::components { -enum class VertexFormat : uint8_t -{ +export enum class VertexFormat: std::uint8_t { r32_g32_b32_sfloat, r32_g32_sfloat, }; -enum class VertexInputRate : uint8_t -{ +export enum class VertexInputRate: std::uint8_t { per_vertex, per_instance, }; -struct VertexInputAttributeDescriptipn +export struct VertexInputAttributeDescriptipn { - uint32_t location; + std::uint32_t location; - uint32_t binding; + std::uint32_t binding; - uint32_t offset; + std::uint32_t offset; VertexFormat format; }; -struct VertexInputBindingDescription +export struct VertexInputBindingDescription { - uint32_t binding; + std::uint32_t binding; - uint32_t stride; + std::uint32_t stride; }; /** Requires a math::components::Transform component on the same entity to be functional. */ -struct Sprite +export struct Sprite { struct Vertex { diff --git a/modules/renderer/public/data/frame_constants.hpp b/modules/renderer/data.cppm similarity index 66% rename from modules/renderer/public/data/frame_constants.hpp rename to modules/renderer/data.cppm index f6ae0b8..89bb6a0 100644 --- a/modules/renderer/public/data/frame_constants.hpp +++ b/modules/renderer/data.cppm @@ -1,10 +1,10 @@ -#pragma once +export module renderer.data; #include namespace lt::renderer { -struct FrameConstants +export struct FrameConstants { math::mat4 view_projection; }; diff --git a/modules/renderer/private/frontend/context/device.hpp b/modules/renderer/frontend/context/device.cppm similarity index 61% rename from modules/renderer/private/frontend/context/device.hpp rename to modules/renderer/frontend/context/device.cppm index afa7634..3b1e21b 100644 --- a/modules/renderer/private/frontend/context/device.hpp +++ b/modules/renderer/frontend/context/device.cppm @@ -1,16 +1,9 @@ -#pragma once - -#include -#include - +export module.renderer.frontend.device; namespace lt::renderer { class IDevice { public: - [[nodiscard]] static auto create(Api target_api, class IGpu *gpu, class ISurface *surface) - -> memory::Scope; - IDevice() = default; virtual ~IDevice() = default; diff --git a/modules/renderer/private/frontend/context/device.test.cpp b/modules/renderer/frontend/context/device.test.cpp similarity index 100% rename from modules/renderer/private/frontend/context/device.test.cpp rename to modules/renderer/frontend/context/device.test.cpp diff --git a/modules/renderer/private/frontend/context/gpu.hpp b/modules/renderer/frontend/context/gpu.cppm similarity index 59% rename from modules/renderer/private/frontend/context/gpu.hpp rename to modules/renderer/frontend/context/gpu.cppm index 47ede20..24d9754 100644 --- a/modules/renderer/private/frontend/context/gpu.hpp +++ b/modules/renderer/frontend/context/gpu.cppm @@ -1,16 +1,10 @@ -#pragma once - -#include -#include +export module renderer.frontend.gpu; namespace lt::renderer { -class IGpu +export class IGpu { public: - [[nodiscard]] static auto create(Api target_api, class IInstance *instance) - -> memory::Scope; - IGpu() = default; virtual ~IGpu() = default; diff --git a/modules/renderer/private/frontend/context/instance.hpp b/modules/renderer/frontend/context/instance.cppm similarity index 68% rename from modules/renderer/private/frontend/context/instance.hpp rename to modules/renderer/frontend/context/instance.cppm index 907af7c..85af17a 100644 --- a/modules/renderer/private/frontend/context/instance.hpp +++ b/modules/renderer/frontend/context/instance.cppm @@ -1,13 +1,12 @@ -#pragma once - -#include +export module renderer.frontend.instance; +import renderer.api; namespace lt::renderer { -class IInstance +export class IInstance { public: - [[nodiscard]] static auto get(Api target_api) -> IInstance *; + // [[nodiscard]] static auto get(Api target_api) -> IInstance *; IInstance() = default; virtual ~IInstance() = default; diff --git a/modules/renderer/private/frontend/context/surface.hpp b/modules/renderer/frontend/context/surface.cppm similarity index 56% rename from modules/renderer/private/frontend/context/surface.hpp rename to modules/renderer/frontend/context/surface.cppm index 60f6492..3b44795 100644 --- a/modules/renderer/private/frontend/context/surface.hpp +++ b/modules/renderer/frontend/context/surface.cppm @@ -1,21 +1,14 @@ -#pragma once - -#include -#include -#include -#include +export module renderer.frontend.surface; +import ecs.entity; +import math.vec2; +import renderer.api; +import memory.scope; namespace lt::renderer { -class ISurface +export class ISurface { public: - [[nodiscard]] static auto create( - Api target_api, - class IInstance *instance, - const ecs::Entity &surface_entity - ) -> memory::Scope; - ISurface() = default; virtual ~ISurface() = default; diff --git a/modules/renderer/private/frontend/context/surface.test.cpp b/modules/renderer/frontend/context/surface.test.cpp similarity index 100% rename from modules/renderer/private/frontend/context/surface.test.cpp rename to modules/renderer/frontend/context/surface.test.cpp diff --git a/modules/renderer/private/frontend/context/swapchain.hpp b/modules/renderer/frontend/context/swapchain.cppm similarity index 52% rename from modules/renderer/private/frontend/context/swapchain.hpp rename to modules/renderer/frontend/context/swapchain.cppm index ac35e8d..79437af 100644 --- a/modules/renderer/private/frontend/context/swapchain.hpp +++ b/modules/renderer/frontend/context/swapchain.cppm @@ -29,3 +29,28 @@ public: }; } // namespace lt::renderer + + +#include +#include + +namespace lt::renderer { + +[[nodiscard]] /* static */ auto ISwapchain::create( + Api target_api, + ISurface *surface, + IGpu *gpu, + IDevice *device +) -> memory::Scope +{ + switch (target_api) + { + case Api::vulkan: return memory::create_scope(surface, gpu, device); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } +} + + +} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/data/buffer.cpp b/modules/renderer/frontend/data/buffer.cpp similarity index 100% rename from modules/renderer/private/frontend/data/buffer.cpp rename to modules/renderer/frontend/data/buffer.cpp diff --git a/modules/renderer/private/frontend/data/buffer.hpp b/modules/renderer/frontend/data/buffer.cppm similarity index 100% rename from modules/renderer/private/frontend/data/buffer.hpp rename to modules/renderer/frontend/data/buffer.cppm diff --git a/modules/renderer/private/frontend/data/buffer.test.cpp b/modules/renderer/frontend/data/buffer.test.cpp similarity index 100% rename from modules/renderer/private/frontend/data/buffer.test.cpp rename to modules/renderer/frontend/data/buffer.test.cpp diff --git a/modules/renderer/public/frontend/messenger.hpp b/modules/renderer/frontend/messenger.cppm similarity index 53% rename from modules/renderer/public/frontend/messenger.hpp rename to modules/renderer/frontend/messenger.cppm index be73ad5..1193d47 100644 --- a/modules/renderer/public/frontend/messenger.hpp +++ b/modules/renderer/frontend/messenger.cppm @@ -1,16 +1,16 @@ -#pragma once - -#include -#include -#include -#include +export module renderer.frontend.messenger; +import debug.assertions; +import memory.scope; +import renderer.api; +import bitwise; +import std; namespace lt::renderer { -class IMessenger +export class IMessenger { public: - enum class MessageSeverity : uint8_t + enum class MessageSeverity : std::uint8_t { none = 0u, @@ -22,7 +22,7 @@ public: all = verbose | info | warning | error, }; - enum class MessageType : uint8_t + enum class MessageType : std::uint8_t { none = 0u, general = bitwise::bit(0u), @@ -72,3 +72,32 @@ public: }; } // namespace lt::renderer + +module :private; +using namespace lt::renderer; + +import renderer.backends.vk.messenger; + +[[nodiscard]] /* static */ auto IMessenger::create( + Api target_api, + IInstance *instance, + CreateInfo info +) -> memory::Scope +{ + debug::ensure( + info.severities != MessageSeverity::none, + "Failed to create vk::Messenger: severities == none" + ); + + debug::ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none"); + + debug::ensure(info.callback, "Failed to create vk::Messenger: null callback"); + + switch (target_api) + { + case Api::vulkan: return memory::create_scope(instance, std::move(info)); + case Api::none: + case Api::metal: + case Api::direct_x: throw std::runtime_error { "Invalid API" }; + } +} diff --git a/modules/renderer/private/frontend/renderer/pass.cpp b/modules/renderer/frontend/renderer/pass.cpp similarity index 100% rename from modules/renderer/private/frontend/renderer/pass.cpp rename to modules/renderer/frontend/renderer/pass.cpp diff --git a/modules/renderer/private/frontend/renderer/pass.hpp b/modules/renderer/frontend/renderer/pass.cppm similarity index 100% rename from modules/renderer/private/frontend/renderer/pass.hpp rename to modules/renderer/frontend/renderer/pass.cppm diff --git a/modules/renderer/private/frontend/renderer/pass.test.cpp b/modules/renderer/frontend/renderer/pass.test.cpp similarity index 100% rename from modules/renderer/private/frontend/renderer/pass.test.cpp rename to modules/renderer/frontend/renderer/pass.test.cpp diff --git a/modules/renderer/private/frontend/renderer/renderer.cpp b/modules/renderer/frontend/renderer/renderer.cpp similarity index 100% rename from modules/renderer/private/frontend/renderer/renderer.cpp rename to modules/renderer/frontend/renderer/renderer.cpp diff --git a/modules/renderer/private/frontend/renderer/renderer.hpp b/modules/renderer/frontend/renderer/renderer.cppm similarity index 100% rename from modules/renderer/private/frontend/renderer/renderer.hpp rename to modules/renderer/frontend/renderer/renderer.cppm diff --git a/modules/renderer/private/frontend/renderer/renderer.test.cpp b/modules/renderer/frontend/renderer/renderer.test.cpp similarity index 100% rename from modules/renderer/private/frontend/renderer/renderer.test.cpp rename to modules/renderer/frontend/renderer/renderer.test.cpp diff --git a/modules/renderer/private/backend/vk/context/device.hpp b/modules/renderer/private/backend/vk/context/device.hpp deleted file mode 100644 index 7050ae6..0000000 --- a/modules/renderer/private/backend/vk/context/device.hpp +++ /dev/null @@ -1,260 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace lt::renderer::vk { - -class Device: public IDevice -{ -public: - Device(IGpu *gpu, ISurface *surface); - - ~Device() override; - - Device(Device &&) = default; - - Device(const Device &) = delete; - - auto operator=(Device &&) -> Device & = default; - - auto operator=(const Device &) const -> Device & = delete; - - [[nodiscard]] auto vk() const -> VkDevice - { - return m_device; - } - - [[nodiscard]] auto get_family_indices() const -> std::array - { - return { m_graphics_queue_family_index, m_present_queue_family_index }; - } - - [[nodiscard]] auto get_graphics_queue() const -> VkQueue - { - return m_graphics_queue; - } - - [[nodiscard]] auto get_present_queue() const -> VkQueue - { - return m_present_queue; - } - - /** utilities */ - template - void name(const T &object, std::format_string fmt, Args &&...args) - { - const auto name = std::format(fmt, std::forward(args)...); - auto info = VkDebugUtilsObjectNameInfoEXT { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, - .objectType = get_object_type(object), - .objectHandle = (uint64_t)(object), - .pObjectName = name.c_str(), - }; - - vk_set_debug_object_name(m_device, &info); - } - - template - void name(const T &object, const char *name) - { - auto info = VkDebugUtilsObjectNameInfoEXT { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, - .objectType = get_object_type(object), - .objectHandle = (uint64_t)(object), - .pObjectName = name, - }; - - vk_set_debug_object_name(m_device, &info); - } - - - /** work functions */ - void submit(VkSubmitInfo info, VkFence fence) const; - - void present(VkPresentInfoKHR info) const; - - void wait_idle() const; - - void wait_for_fence(VkFence fence) const; - - void wait_for_fences(std::span fences) const; - - void reset_fence(VkFence fence) const; - - void reset_fences(std::span fences) const; - - /** getter functions */ - [[nodiscard]] auto acquire_image( - VkSwapchainKHR swapchain, - VkSemaphore semaphore, - uint64_t timeout = 100'000'000 - ) -> std::optional; - - [[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector; - - [[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements; - - /** binders / mappers */ - void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const; - - [[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const - -> std::span; - - void unmap_memory(VkDeviceMemory memory); - - /** create functions */ - [[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR; - - [[nodiscard]] auto create_framebuffer(VkFramebufferCreateInfo info) const -> VkFramebuffer; - - [[nodiscard]] auto create_image_view(VkImageViewCreateInfo info) const -> VkImageView; - - [[nodiscard]] auto create_graphics_pipeline(VkGraphicsPipelineCreateInfo info) const - -> VkPipeline; - - [[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass; - - [[nodiscard]] auto create_pipeline_layout( - std::vector descriptor_set_layout, - std::vector push_constant_ranges - ) const -> VkPipelineLayout; - - [[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule; - - [[nodiscard]] auto create_command_pool(VkCommandPoolCreateInfo info) const -> VkCommandPool; - - [[nodiscard]] auto create_semaphores(uint32_t count) const -> std::vector; - - [[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const - -> std::vector; - - [[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer; - - [[nodiscard]] auto create_descriptor_set_layout(VkDescriptorSetLayoutCreateInfo info) const - -> VkDescriptorSetLayout; - - [[nodiscard]] auto create_desscriptor_pool(VkDescriptorPoolCreateInfo info) const - -> VkDescriptorPool; - - /** allocation functions */ - [[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory; - - [[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const - -> std::vector; - - [[nodiscard]] auto allocate_descriptor_set(VkDescriptorSetAllocateInfo info) const - -> VkDescriptorSet; - - /** de-allocation functions */ - void free_memory(VkDeviceMemory memory) const; - - void free_descriptor_set( - VkDescriptorPool descriptor_pool, - VkDescriptorSet descriptor_set - ) const; - - /** destroy functions */ - void destroy_swapchain(VkSwapchainKHR swapchain) const; - - void destroy_framebuffer(VkFramebuffer framebuffer) const; - - void destroy_framebuffers(std::span framebuffers) const; - - void destroy_image_view(VkImageView image_view) const; - - void destroy_image_views(std::span image_views) const; - - void destroy_pipeline(VkPipeline pipeline) const; - - void destroy_pass(VkRenderPass pass) const; - - void destroy_pipeline_layout(VkPipelineLayout pipeline_layout) const; - - void destroy_shader_module(VkShaderModule shader_module) const; - - void destroy_command_pool(VkCommandPool command_pool) const; - - void destroy_semaphore(VkSemaphore semaphore) const; - - void destroy_semaphores(std::span semaphores) const; - - void destroy_fence(VkFence fence) const; - - void destroy_fences(std::span fences) const; - - void destroy_buffer(VkBuffer buffer) const; - - void destroy_descriptor_set_layout(VkDescriptorSetLayout layout) const; - - void destroy_descriptor_pool(VkDescriptorPool pool) const; - -private: - template - static auto get_object_type(const T &object) -> VkObjectType - { - std::ignore = object; - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_QUEUE; - } - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_FENCE; - } - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_SEMAPHORE; - } - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_SWAPCHAIN_KHR; - } - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_IMAGE; - } - - if constexpr (std::is_same_v) - { - return VK_OBJECT_TYPE_IMAGE_VIEW; - } - - static_assert("invalid type"); - } - - - void initialize_physical_device(); - - void initialize_logical_device(); - - void initialize_queue_indices(); - - [[nodiscard]] auto find_suitable_queue_family() const -> uint32_t; - - memory::NullOnMove m_gpu {}; - - class Surface *m_surface {}; - - VkAllocationCallbacks *m_allocator = nullptr; - - VkDevice m_device = VK_NULL_HANDLE; - - VkQueue m_graphics_queue = VK_NULL_HANDLE; - - VkQueue m_present_queue = VK_NULL_HANDLE; - - uint32_t m_graphics_queue_family_index = VK_QUEUE_FAMILY_IGNORED; - - uint32_t m_present_queue_family_index = VK_QUEUE_FAMILY_IGNORED; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/gpu.cpp b/modules/renderer/private/backend/vk/context/gpu.cpp deleted file mode 100644 index 1644cf1..0000000 --- a/modules/renderer/private/backend/vk/context/gpu.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include -#include - -namespace lt::renderer::vk { - -Gpu::Gpu(IInstance *instance) - : m_descriptor_indexing_features( - { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES } - ) -{ - auto gpus = static_cast(instance)->enumerate_gpus(); - - for (auto &gpu : gpus) - { - auto properties = VkPhysicalDeviceProperties {}; - auto features = VkPhysicalDeviceFeatures2 { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, - .pNext = &m_descriptor_indexing_features - }; - - vk_get_physical_device_properties(gpu, &properties); - vk_get_physical_device_features(gpu, &features); - - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - && features.features.geometryShader) - { - m_gpu = gpu; - } - } - ensure(m_gpu, "Failed to find any suitable Vulkan physical device"); - - - vk_get_physical_device_memory_properties(m_gpu, &m_memory_properties); - - auto count = uint32_t { 0u }; - vk_get_physical_device_queue_family_properties(m_gpu, &count, nullptr); - m_queue_family_properties.resize(count); - vk_get_physical_device_queue_family_properties(m_gpu, &count, m_queue_family_properties.data()); -} - -[[nodiscard]] auto Gpu::queue_family_supports_presentation( - VkSurfaceKHR surface, - uint32_t queue_family_idx -) -> bool -{ - auto supported = VkBool32 { false }; - vkc(vk_get_physical_device_surface_support(m_gpu, queue_family_idx, surface, &supported)); - - return supported; -} - -[[nodiscard]] auto Gpu::get_surface_capabilities(VkSurfaceKHR surface) const - -> VkSurfaceCapabilitiesKHR -{ - auto capabilities = VkSurfaceCapabilitiesKHR {}; - vkc(vk_get_physical_device_surface_capabilities(m_gpu, surface, &capabilities)); - return capabilities; -} - -[[nodiscard]] auto Gpu::get_surface_formats(VkSurfaceKHR surface) const - -> std::vector -{ - auto count = uint32_t { 0u }; - vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, nullptr)); - - auto formats = std::vector(count); - vkc(vk_get_physical_device_surface_formats(m_gpu, surface, &count, formats.data())); - - return formats; -} - -[[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice -{ - auto *device = VkDevice {}; - vkc(vk_create_device(m_gpu, &info, nullptr, &device)); - return device; -} - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/gpu.hpp b/modules/renderer/private/backend/vk/context/gpu.hpp deleted file mode 100644 index ff8e035..0000000 --- a/modules/renderer/private/backend/vk/context/gpu.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace lt::renderer::vk { - -class Gpu: public IGpu -{ -public: - Gpu(IInstance *instance); - - [[nodiscard]] auto queue_family_supports_presentation( - VkSurfaceKHR surface, - uint32_t queue_family_idx - ) -> bool; - - [[nodiscard]] auto get_surface_capabilities(VkSurfaceKHR surface) const - -> VkSurfaceCapabilitiesKHR; - - [[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const - -> std::vector; - - [[nodiscard]] auto create_device(VkDeviceCreateInfo info) const -> VkDevice; - - [[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties - { - return m_properties; - } - - [[nodiscard]] auto get_descriptor_indexing_features() const - -> VkPhysicalDeviceDescriptorIndexingFeatures - { - return m_descriptor_indexing_features; - } - - [[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties - { - return m_memory_properties; - } - - [[nodiscard]] auto get_queue_family_properties() const -> std::vector - { - return m_queue_family_properties; - } - -private: - memory::NullOnMove m_gpu = VK_NULL_HANDLE; - - VkPhysicalDeviceProperties m_properties {}; - - VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features; - - VkPhysicalDeviceMemoryProperties m_memory_properties {}; - - std::vector m_queue_family_properties; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/instance.cpp b/modules/renderer/private/backend/vk/context/instance.cpp deleted file mode 100644 index fabd48b..0000000 --- a/modules/renderer/private/backend/vk/context/instance.cpp +++ /dev/null @@ -1,457 +0,0 @@ -#include -#include -#include -#include - -#if defined(_WIN32) - #error "Unsupported platform (currently)" -#elif defined(__unix__) - #include -namespace { -void *library = nullptr; // NOLINT -} -#endif - -namespace lt::renderer::vk { - -// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) -// global functions -PFN_vkGetInstanceProcAddr vk_get_instance_proc_address {}; -PFN_vkCreateInstance vk_create_instance {}; -PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties {}; -PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties {}; - -// instance functions -PFN_vkDestroyInstance vk_destroy_instance {}; -PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices {}; -PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties {}; -PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties {}; -PFN_vkCreateDevice vk_create_device {}; -PFN_vkGetDeviceProcAddr vk_get_device_proc_address {}; -PFN_vkDestroyDevice vk_destroy_device {}; -PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {}; -PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {}; -PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {}; - -// extension instance functions -PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {}; -PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label {}; -PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label {}; -PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger {}; -PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger {}; -PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label {}; -PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label {}; -PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label {}; -PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name {}; -PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag {}; -PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message {}; - -// device functions -PFN_vkGetDeviceQueue vk_get_device_queue {}; -PFN_vkCreateCommandPool vk_create_command_pool {}; -PFN_vkDestroyCommandPool vk_destroy_command_pool {}; -PFN_vkAllocateCommandBuffers vk_allocate_command_buffers {}; -PFN_vkFreeCommandBuffers vk_free_command_buffers {}; -PFN_vkBeginCommandBuffer vk_begin_command_buffer {}; -PFN_vkEndCommandBuffer vk_end_command_buffer {}; -PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier {}; -PFN_vkQueueSubmit vk_queue_submit {}; -PFN_vkQueueWaitIdle vk_queue_wait_idle {}; -PFN_vkDeviceWaitIdle vk_device_wait_idle {}; -PFN_vkCreateFence vk_create_fence {}; -PFN_vkDestroyFence vk_destroy_fence {}; -PFN_vkWaitForFences vk_wait_for_fences {}; -PFN_vkResetFences vk_reset_fences {}; -PFN_vkCreateSemaphore vk_create_semaphore {}; -PFN_vkDestroySemaphore vk_destroy_semaphore {}; -PFN_vkCreateSwapchainKHR vk_create_swapchain_khr {}; -PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr {}; -PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr {}; -PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr {}; -PFN_vkQueuePresentKHR vk_queue_present_khr {}; -PFN_vkCreateImageView vk_create_image_view {}; -PFN_vkDestroyImageView vk_destroy_image_view {}; -PFN_vkCreateRenderPass vk_create_render_pass {}; -PFN_vkDestroyRenderPass vk_destroy_render_pass {}; -PFN_vkCreateFramebuffer vk_create_frame_buffer {}; -PFN_vkDestroyFramebuffer vk_destroy_frame_buffer {}; -PFN_vkCreateShaderModule vk_create_shader_module {}; -PFN_vkDestroyShaderModule vk_destroy_shader_module {}; -PFN_vkCreatePipelineLayout vk_create_pipeline_layout {}; -PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout {}; -PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines {}; -PFN_vkDestroyPipeline vk_destroy_pipeline {}; -PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass {}; -PFN_vkCmdEndRenderPass vk_cmd_end_render_pass {}; -PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {}; -PFN_vkCmdDraw vk_cmd_draw {}; -PFN_vkCmdSetViewport vk_cmd_set_viewport {}; -PFN_vkCmdSetScissor vk_cmd_set_scissors {}; -PFN_vkCmdPushConstants vk_cmd_push_constants {}; -PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {}; - -PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {}; -PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {}; -PFN_vkCreateDescriptorPool vk_create_descriptor_pool {}; -PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {}; -PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {}; -PFN_vkFreeDescriptorSets vk_free_descriptor_sets {}; - -PFN_vkCreateBuffer vk_create_buffer {}; -PFN_vkDestroyBuffer vk_destroy_buffer {}; -PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {}; -PFN_vkAllocateMemory vk_allocate_memory {}; -PFN_vkBindBufferMemory vk_bind_buffer_memory {}; -PFN_vkMapMemory vk_map_memory {}; -PFN_vkUnmapMemory vk_unmap_memory {}; -PFN_vkFreeMemory vk_free_memory {}; - -PFN_vkResetCommandBuffer vk_reset_command_buffer {}; - -PFN_vkCmdBeginRendering vk_cmd_begin_rendering {}; -PFN_vkCmdEndRendering vk_cmd_end_rendering {}; - -PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {}; -PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {}; -PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {}; - -auto vk_create_xlib_surface_khr = PFN_vkCreateXlibSurfaceKHR {}; -auto vk_destroy_surface_khr = PFN_vkDestroySurfaceKHR {}; - -// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - -Instance::Instance() -{ - load_library(); - load_global_functions(); - - initialize_instance(); - load_instance_functions(); -} - -Instance::~Instance() -{ - vk_destroy_instance(m_instance, nullptr); - unload_library(); -} - -void Instance::initialize_instance() -{ - auto app_info = VkApplicationInfo { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pApplicationName = "Hallo Hallo Hallo :3", - .applicationVersion = VK_MAKE_VERSION(1, 4, 0), - .pEngineName = "light", - .engineVersion = VK_MAKE_VERSION(1, 4, 0), - .apiVersion = VK_API_VERSION_1_4, - }; - - auto extensions = std::vector { - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - VK_KHR_SURFACE_EXTENSION_NAME, - VK_KHR_XLIB_SURFACE_EXTENSION_NAME, - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, - }; - - const char *layer_name = "VK_LAYER_KHRONOS_validation"; - const auto setting_validate_core = VkBool32 { VK_TRUE }; - const auto setting_validate_sync = VkBool32 { VK_TRUE }; - const auto setting_thread_safety = VkBool32 { VK_TRUE }; - const auto *setting_debug_action = ""; - const auto setting_enable_message_limit = VkBool32 { VK_TRUE }; - const auto setting_duplicate_message_limit = uint32_t { UINT32_MAX }; - auto setting_report_flags = std::array { - "info", "warn", "perf", "error", "verbose", - }; - - const auto settings = std::array({ - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "validate_core", - .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT, - .valueCount = 1, - .pValues = &setting_validate_core, - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "validate_sync", - .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT, - .valueCount = 1, - .pValues = &setting_validate_sync, - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "thread_safety", - .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT, - .valueCount = 1, - .pValues = &setting_thread_safety, - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "debug_action", - .type = VK_LAYER_SETTING_TYPE_STRING_EXT, - .valueCount = 1, - .pValues = static_cast(&setting_debug_action), - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "report_flags", - .type = VK_LAYER_SETTING_TYPE_STRING_EXT, - .valueCount = setting_report_flags.size(), - .pValues = static_cast(setting_report_flags.data()), - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "enable_message_limit", - .type = VK_LAYER_SETTING_TYPE_BOOL32_EXT, - .valueCount = 1, - .pValues = &setting_enable_message_limit, - }, - VkLayerSettingEXT { - .pLayerName = layer_name, - .pSettingName = "duplicate_message_limit", - .type = VK_LAYER_SETTING_TYPE_UINT32_EXT, - .valueCount = 1u, - .pValues = &setting_duplicate_message_limit, - }, - }); - - const VkLayerSettingsCreateInfoEXT layer_settings_create_info = { - .sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT, - .settingCount = settings.size(), - .pSettings = settings.data(), - }; - - auto layers = std::vector { - "VK_LAYER_KHRONOS_validation", - }; - - auto instance_info = VkInstanceCreateInfo { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = &layer_settings_create_info, - .pApplicationInfo = &app_info, - .enabledLayerCount = static_cast(layers.size()), - .ppEnabledLayerNames = layers.data(), - .enabledExtensionCount = static_cast(extensions.size()), - .ppEnabledExtensionNames = extensions.data(), - }; - - { - auto count = 0u; - vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr)); - - auto extensions = std::vector(count); - memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties)); - vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data())); - - // log::info("Available vulkan instance extensions:"); - for (auto &ext : extensions) - { - // log::info("\t{} @ {}", ext.extensionName, ext.specVersion); - } - } - - vkc(vk_create_instance(&instance_info, nullptr, &m_instance)); - ensure(m_instance, "Failed to create vulkan instance"); -} - -void Instance::load_library() -{ - constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE; - library = dlopen("libvulkan.so.1", runtime_loader_flags); - if (!library) - { - library = dlopen("libvulkan.so", runtime_loader_flags); - } - ensure(library, "Failed to dlopen vulkan library"); - - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - vk_get_instance_proc_address = reinterpret_cast( - dlsym(library, "vkGetInstanceProcAddr") - ); - ensure(vk_get_instance_proc_address, "Failed to load vulkan function: vkGetInstanceProcAddr"); -} - -void Instance::unload_library() -{ - if (!library) - { - return; - } - - // calling dlclose causes many issues with runtime analyzers - // eg. https://github.com/google/sanitizers/issues/89 - // with no noticable gains, so we just don't bother closing it. - - // dlclose(library); - // library = nullptr; -} - -void Instance::load_global_functions() -{ - constexpr auto load_fn = [](T &pfn, const char *fn_name) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - pfn = reinterpret_cast(vk_get_instance_proc_address(nullptr, fn_name)); - ensure(pfn, "Failed to load vulkan global function: {}", fn_name); - // log::trace("Loaded global function: {}", fn_name); - }; - - load_fn(vk_create_instance, "vkCreateInstance"); - load_fn(vk_enumerate_instance_extension_properties, "vkEnumerateInstanceExtensionProperties"); - load_fn(vk_enumerate_instance_layer_properties, "vkEnumerateInstanceLayerProperties"); -} - -void Instance::load_instance_functions() -{ - const auto load_fn = [&](T &pfn, const char *fn_name) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - pfn = reinterpret_cast(vk_get_instance_proc_address(m_instance, fn_name)); - ensure(pfn, "Failed to load vulkan instance function: {}", fn_name); - // log::trace("Loaded instance function: {}", fn_name); - }; - - load_fn(vk_destroy_instance, "vkDestroyInstance"); - load_fn(vk_enumerate_physical_devices, "vkEnumeratePhysicalDevices"); - load_fn(vk_get_physical_device_properties, "vkGetPhysicalDeviceProperties"); - load_fn( - vk_get_physical_device_queue_family_properties, - "vkGetPhysicalDeviceQueueFamilyProperties" - ); - load_fn(vk_create_device, "vkCreateDevice"); - load_fn(vk_get_device_proc_address, "vkGetDeviceProcAddr"); - load_fn(vk_destroy_device, "vkDestroyDevice"); - load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures"); - load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties"); - load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties"); - - load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT"); - load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT"); - load_fn(vk_cmd_insert_debug_label, "vkCmdInsertDebugUtilsLabelEXT"); - load_fn(vk_create_debug_messenger, "vkCreateDebugUtilsMessengerEXT"); - load_fn(vk_destroy_debug_messenger, "vkDestroyDebugUtilsMessengerEXT"); - load_fn(vk_queue_begin_debug_label, "vkQueueBeginDebugUtilsLabelEXT"); - load_fn(vk_queue_end_debug_label, "vkQueueEndDebugUtilsLabelEXT"); - load_fn(vk_queue_insert_debug_label, "vkQueueInsertDebugUtilsLabelEXT"); - load_fn(vk_set_debug_object_name, "vkSetDebugUtilsObjectNameEXT"); - load_fn(vk_set_debug_object_tag, "vkSetDebugUtilsObjectTagEXT"); - load_fn(vk_submit_debug_message, "vkSubmitDebugUtilsMessageEXT"); - - load_fn(vk_get_physical_device_surface_support, "vkGetPhysicalDeviceSurfaceSupportKHR"); - load_fn( - vk_get_physical_device_surface_capabilities, - "vkGetPhysicalDeviceSurfaceCapabilitiesKHR" - ); - load_fn(vk_get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR"); - load_fn(vk_create_xlib_surface_khr, "vkCreateXlibSurfaceKHR"); - load_fn(vk_destroy_surface_khr, "vkDestroySurfaceKHR"); -} - -void Instance::load_device_functions_impl(VkDevice device) -{ - const auto load_fn = [&](T &pfn, const char *fn_name) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - pfn = reinterpret_cast(vk_get_device_proc_address(device, fn_name)); - ensure(pfn, "Failed to load vulkan device function: {}", fn_name); - // log::trace("Loaded device function: {}", fn_name); - }; - - load_fn(vk_get_device_queue, "vkGetDeviceQueue"); - load_fn(vk_create_command_pool, "vkCreateCommandPool"); - load_fn(vk_destroy_command_pool, "vkDestroyCommandPool"); - load_fn(vk_allocate_command_buffers, "vkAllocateCommandBuffers"); - load_fn(vk_free_command_buffers, "vkFreeCommandBuffers"); - load_fn(vk_begin_command_buffer, "vkBeginCommandBuffer"); - load_fn(vk_end_command_buffer, "vkEndCommandBuffer"); - load_fn(vk_cmd_pipeline_barrier, "vkCmdPipelineBarrier"); - load_fn(vk_queue_submit, "vkQueueSubmit"); - load_fn(vk_queue_wait_idle, "vkQueueWaitIdle"); - load_fn(vk_device_wait_idle, "vkDeviceWaitIdle"); - load_fn(vk_create_fence, "vkCreateFence"); - load_fn(vk_destroy_fence, "vkDestroyFence"); - load_fn(vk_wait_for_fences, "vkWaitForFences"); - load_fn(vk_reset_fences, "vkResetFences"); - load_fn(vk_create_semaphore, "vkCreateSemaphore"); - load_fn(vk_destroy_semaphore, "vkDestroySemaphore"); - load_fn(vk_create_swapchain_khr, "vkCreateSwapchainKHR"); - load_fn(vk_destroy_swapchain_khr, "vkDestroySwapchainKHR"); - load_fn(vk_get_swapchain_images_khr, "vkGetSwapchainImagesKHR"); - load_fn(vk_acquire_next_image_khr, "vkAcquireNextImageKHR"); - load_fn(vk_queue_present_khr, "vkQueuePresentKHR"); - load_fn(vk_create_image_view, "vkCreateImageView"); - load_fn(vk_destroy_image_view, "vkDestroyImageView"); - load_fn(vk_create_render_pass, "vkCreateRenderPass"); - load_fn(vk_destroy_render_pass, "vkDestroyRenderPass"); - load_fn(vk_create_frame_buffer, "vkCreateFramebuffer"); - load_fn(vk_destroy_frame_buffer, "vkDestroyFramebuffer"); - load_fn(vk_create_shader_module, "vkCreateShaderModule"); - load_fn(vk_destroy_shader_module, "vkDestroyShaderModule"); - load_fn(vk_create_pipeline_layout, "vkCreatePipelineLayout"); - load_fn(vk_destroy_pipeline_layout, "vkDestroyPipelineLayout"); - load_fn(vk_create_graphics_pipelines, "vkCreateGraphicsPipelines"); - load_fn(vk_destroy_pipeline, "vkDestroyPipeline"); - load_fn(vk_cmd_begin_render_pass, "vkCmdBeginRenderPass"); - load_fn(vk_cmd_end_render_pass, "vkCmdEndRenderPass"); - load_fn(vk_cmd_bind_pipeline, "vkCmdBindPipeline"); - load_fn(vk_cmd_draw, "vkCmdDraw"); - load_fn(vk_cmd_set_viewport, "vkCmdSetViewport"); - load_fn(vk_cmd_set_scissors, "vkCmdSetScissor"); - load_fn(vk_cmd_push_constants, "vkCmdPushConstants"); - load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer"); - load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout"); - load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout"); - load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool"); - load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool"); - load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets"); - load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets"); - load_fn(vk_create_buffer, "vkCreateBuffer"); - load_fn(vk_destroy_buffer, "vkDestroyBuffer"); - load_fn(vk_allocate_memory, "vkAllocateMemory"); - load_fn(vk_bind_buffer_memory, "vkBindBufferMemory"); - load_fn(vk_map_memory, "vkMapMemory"); - load_fn(vk_unmap_memory, "vkUnmapMemory"); - load_fn(vk_free_memory, "vkFreeMemory"); - load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements"); - load_fn(vk_reset_command_buffer, "vkResetCommandBuffer"); - - load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering"); - load_fn(vk_cmd_end_rendering, "vkCmdEndRendering"); -} - -auto Instance::enumerate_gpus() const -> std::vector -{ - auto count = 0u; - vkc(vk_enumerate_physical_devices(m_instance, &count, nullptr)); - ensure(count != 0u, "Failed to find any gpus with Vulkan support"); - - auto gpus = std::vector(count); - vkc(vk_enumerate_physical_devices(m_instance, &count, gpus.data())); - return gpus; -} - -auto Instance::create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR -{ - auto *value = VkSurfaceKHR {}; - vk_create_xlib_surface_khr(m_instance, &info, m_allocator, &value); - - return value; -} - -[[nodiscard]] auto Instance::create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const - -> VkDebugUtilsMessengerEXT -{ - auto *messenger = VkDebugUtilsMessengerEXT {}; - vkc(vk_create_debug_messenger(m_instance, &info, m_allocator, &messenger)); - return messenger; -} - -void Instance::destroy_surface(VkSurfaceKHR surface) const -{ - vk_destroy_surface_khr(m_instance, surface, m_allocator); -} - -void Instance::destroy_messenger(VkDebugUtilsMessengerEXT messenger) const -{ - vk_destroy_debug_messenger(m_instance, messenger, m_allocator); -} - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/instance.hpp b/modules/renderer/private/backend/vk/context/instance.hpp deleted file mode 100644 index 05e7a76..0000000 --- a/modules/renderer/private/backend/vk/context/instance.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include -#include - -namespace lt::renderer::vk { - -/** - * Responsible for dynamically loading Vulkan library/functions. - * - * @note: The delayed vkInstance destruction is due to a work-around for a libx11 quirk: - * @ref: - * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/commit/0017308648b6bf8eef10ef0ffb9470576c0c2e9e - * https://www.xfree86.org/4.7.0/DRI11.html - * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1894 - */ -class Instance: public IInstance -{ -public: - static auto get() -> IInstance * - { - return &Instance::instance(); - } - - static auto load_device_functions(VkDevice device) - { - static_cast(instance()).load_device_functions_impl(device); - } - - ~Instance() override; - - Instance(Instance &&) = delete; - - Instance(const Instance &) = delete; - - auto operator=(const Instance &) -> Instance & = delete; - - auto operator=(Instance &&) -> Instance & = delete; - - [[nodiscard]] auto vk() const -> VkInstance - { - return m_instance; - } - - /* create functions */ - [[nodiscard]] auto create_xlib_surface(VkXlibSurfaceCreateInfoKHR info) const -> VkSurfaceKHR; - - [[nodiscard]] auto create_messenger(VkDebugUtilsMessengerCreateInfoEXT info) const - -> VkDebugUtilsMessengerEXT; - - /* destroy functions */ - void destroy_surface(VkSurfaceKHR surface) const; - - void destroy_messenger(VkDebugUtilsMessengerEXT messenger) const; - - [[nodiscard]] auto enumerate_gpus() const -> std::vector; - -private: - static auto instance() -> IInstance & - { - static auto instance = Instance {}; - return instance; - } - - Instance(); - - void initialize_instance(); - - void load_library(); - - void unload_library(); - - void load_global_functions(); - - void load_instance_functions(); - - void load_device_functions_impl(VkDevice device); - VkInstance m_instance = VK_NULL_HANDLE; - - VkAllocationCallbacks *m_allocator = nullptr; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/surface.cpp b/modules/renderer/private/backend/vk/context/surface.cpp deleted file mode 100644 index ea39570..0000000 --- a/modules/renderer/private/backend/vk/context/surface.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include - -namespace lt::renderer::vk { - -Surface::Surface(IInstance *instance, const ecs::Entity &surface_entity) - : m_surface_entity(surface_entity) - , m_instance(static_cast(instance)) -{ - const auto &component = surface_entity.get(); - - ensure(component.get_native_data().display, "Failed to initialize vk::Surface: null x-display"); - ensure(component.get_native_data().window, "Failed to initialize vk::Surface: null x-window"); - - m_surface = m_instance->create_xlib_surface( - VkXlibSurfaceCreateInfoKHR { - .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, - .dpy = component.get_native_data().display, - .window = component.get_native_data().window, - } - ); -} - -Surface::~Surface() -{ - if (!m_instance) - { - return; - } - - m_instance->destroy_surface(m_surface); -} - -[[nodiscard]] auto Surface::get_framebuffer_size() const -> math::uvec2 -{ - return m_surface_entity.get().get_resolution(); -} - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/surface.hpp b/modules/renderer/private/backend/vk/context/surface.hpp deleted file mode 100644 index 2373210..0000000 --- a/modules/renderer/private/backend/vk/context/surface.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace lt::renderer::vk { - -class Instance; - -class Surface: public ISurface -{ -public: - Surface(IInstance *instance, const ecs::Entity &surface_entity); - - ~Surface() override; - - Surface(Surface &&) = default; - - Surface(const Surface &) = delete; - - auto operator=(Surface &&) -> Surface & = default; - - auto operator=(const Surface &) const -> Surface & = delete; - - [[nodiscard]] auto vk() const -> VkSurfaceKHR - { - return m_surface; - } - - [[nodiscard]] auto get_framebuffer_size() const -> math::uvec2 override; - -private: - class Instance *m_instance {}; - - VkSurfaceKHR m_surface = VK_NULL_HANDLE; - - ecs::Entity m_surface_entity; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/context/swapchain.hpp b/modules/renderer/private/backend/vk/context/swapchain.hpp deleted file mode 100644 index ade3cdb..0000000 --- a/modules/renderer/private/backend/vk/context/swapchain.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace lt::renderer::vk { - -class Swapchain: public ISwapchain -{ -public: - Swapchain(ISurface *surface, IGpu *gpu, IDevice *device); - ~Swapchain() override; - - Swapchain(Swapchain &&) = default; - - Swapchain(const Swapchain &) = delete; - - auto operator=(Swapchain &&) -> Swapchain & = default; - - auto operator=(const Swapchain &) const -> Swapchain & = delete; - - [[nodiscard]] auto vk() const -> VkSwapchainKHR - { - return m_swapchain; - } - - [[nodiscard]] auto vk_ptr() -> VkSwapchainKHR * - { - return &m_swapchain; - } - - [[nodiscard]] auto get_resolution() const -> VkExtent2D - { - return m_resolution; - } - - [[nodiscard]] auto get_format() const -> VkFormat - { - return m_format; - } - - [[nodiscard]] auto get_image_count() const -> size_t - { - return m_images.size(); - } - - [[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView - { - return m_image_views[idx]; - } - - [[nodiscard]] auto get_image(uint32_t idx) -> VkImage - { - return m_images[idx]; - } - - - [[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const - -> std::vector; - -private: - [[nodiscard]] auto get_optimal_image_count( - VkSurfaceCapabilitiesKHR capabilities, - uint32_t desired_image_count - ) const -> uint32_t; - - memory::NullOnMove m_surface {}; - - class Gpu *m_gpu {}; - - class Device *m_device {}; - - VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; - - std::vector m_images; - - std::vector m_image_views; - - VkExtent2D m_resolution {}; - - VkFormat m_format {}; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/data/buffer.hpp b/modules/renderer/private/backend/vk/data/buffer.hpp deleted file mode 100644 index f6d4c35..0000000 --- a/modules/renderer/private/backend/vk/data/buffer.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -namespace lt::renderer::vk { - -class Buffer: public IBuffer -{ -public: - Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info); - - [[nodiscard]] auto map() -> std::span override; - - void unmap() override; - - // TODO(Light): this is to make copying possible. - // But it should be removed in the future, - // Right now it's not possible because: buffers can't understand CommandBuffers. - // And I'm not sure how to properly abstract over command buffers, - // before using other APIs... - [[nodiscard]] auto vk() - { - return *m_buffer; - } - - [[nodiscard]] auto get_size() const -> size_t override - { - return m_size; - } - -private: - [[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo; - - [[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags; - - [[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags; - - - [[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const - -> bool; - - [[nodiscard]] auto has_required_memory_properties( - uint32_t required_properties, - uint32_t property_flags - ) const -> bool; - - Device *m_device {}; - - Gpu *m_gpu {}; - - raii::Buffer m_buffer; - - raii::Memory m_memory; - - // TODO(Light): should this reflect the allocation size instead? - size_t m_size {}; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/messenger.hpp b/modules/renderer/private/backend/vk/messenger.hpp deleted file mode 100644 index ce7b662..0000000 --- a/modules/renderer/private/backend/vk/messenger.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace lt::renderer::vk { - -class Messenger: public IMessenger -{ -public: - Messenger(IInstance *instance, CreateInfo info); - -private: - static auto native_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT *callback_data, - void *vulkan_user_data - ) -> VkBool32; - - [[nodiscard]] static auto to_native_severity(MessageSeverity severity) - -> VkDebugUtilsMessageSeverityFlagsEXT; - - [[nodiscard]] static auto from_native_severity(VkDebugUtilsMessageSeverityFlagsEXT severity) - -> MessageSeverity; - - [[nodiscard]] static auto to_native_type(MessageType type) -> VkDebugUtilsMessageTypeFlagsEXT; - - [[nodiscard]] static auto from_native_type(VkDebugUtilsMessageTypeFlagsEXT type) -> MessageType; - - class Instance *m_instance {}; - - raii::DebugMessenger m_debug_messenger; - - MessageSeverity m_severities {}; - - MessageType m_types {}; - - Callback_T m_user_callback; - - std::any m_user_data; -}; - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/utils.hpp b/modules/renderer/private/backend/vk/utils.hpp deleted file mode 100644 index 0a20be4..0000000 --- a/modules/renderer/private/backend/vk/utils.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -namespace lt::renderer::vk { - -inline void vkc(VkResult result) -{ - if (result) - { - throw std::runtime_error { - std::format("Vulkan call failed with result: {}", std::to_underlying(result)) - }; - } -} - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/backend/vk/vulkan.hpp b/modules/renderer/private/backend/vk/vulkan.hpp deleted file mode 100644 index 7977ce0..0000000 --- a/modules/renderer/private/backend/vk/vulkan.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#define VK_NO_PROTOTYPES -#define VK_USE_PLATFORM_XLIB_KHR -#include -#include - -namespace lt::renderer::vk { - -// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) -extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties; -extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties; -extern PFN_vkCreateDevice vk_create_device; -extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address; -extern PFN_vkDestroyDevice vk_destroy_device; -extern PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features; -extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties; -extern PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties; - -// extension instance functions -extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label; -extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label; -extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label; -extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger; -extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger; -extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label; -extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label; -extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label; -extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name; -extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag; -extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message; - -// surface instance functions -extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support; -extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities; -extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats; - -// device functions -extern PFN_vkGetDeviceQueue vk_get_device_queue; -extern PFN_vkCreateCommandPool vk_create_command_pool; -extern PFN_vkDestroyCommandPool vk_destroy_command_pool; -extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers; -extern PFN_vkFreeCommandBuffers vk_free_command_buffers; -extern PFN_vkBeginCommandBuffer vk_begin_command_buffer; -extern PFN_vkEndCommandBuffer vk_end_command_buffer; -extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier; -extern PFN_vkQueueSubmit vk_queue_submit; -extern PFN_vkQueueWaitIdle vk_queue_wait_idle; -extern PFN_vkDeviceWaitIdle vk_device_wait_idle; -extern PFN_vkCreateFence vk_create_fence; -extern PFN_vkDestroyFence vk_destroy_fence; -extern PFN_vkWaitForFences vk_wait_for_fences; -extern PFN_vkResetFences vk_reset_fences; -extern PFN_vkCreateSemaphore vk_create_semaphore; -extern PFN_vkDestroySemaphore vk_destroy_semaphore; -extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr; -extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr; -extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr; -extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr; -extern PFN_vkQueuePresentKHR vk_queue_present_khr; -extern PFN_vkCreateImageView vk_create_image_view; -extern PFN_vkDestroyImageView vk_destroy_image_view; -extern PFN_vkCreateRenderPass vk_create_render_pass; -extern PFN_vkDestroyRenderPass vk_destroy_render_pass; -extern PFN_vkCreateFramebuffer vk_create_frame_buffer; -extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer; -extern PFN_vkCreateShaderModule vk_create_shader_module; -extern PFN_vkDestroyShaderModule vk_destroy_shader_module; -extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout; -extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout; -extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines; -extern PFN_vkDestroyPipeline vk_destroy_pipeline; -extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass; -extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass; -extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline; -extern PFN_vkCmdDraw vk_cmd_draw; -extern PFN_vkCmdSetViewport vk_cmd_set_viewport; -extern PFN_vkCmdSetScissor vk_cmd_set_scissors; -extern PFN_vkCmdPushConstants vk_cmd_push_constants; -extern PFN_vkCmdCopyBuffer vk_cmd_copy_buffer; - -extern PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout; -extern PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout; -extern PFN_vkCreateDescriptorPool vk_create_descriptor_pool; -extern PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool; -extern PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets; -extern PFN_vkFreeDescriptorSets vk_free_descriptor_sets; - -extern PFN_vkCreateBuffer vk_create_buffer; -extern PFN_vkDestroyBuffer vk_destroy_buffer; -extern PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements; -extern PFN_vkAllocateMemory vk_allocate_memory; -extern PFN_vkBindBufferMemory vk_bind_buffer_memory; -extern PFN_vkMapMemory vk_map_memory; -extern PFN_vkUnmapMemory vk_unmap_memory; -extern PFN_vkFreeMemory vk_free_memory; - -extern PFN_vkResetCommandBuffer vk_reset_command_buffer; - -extern PFN_vkCmdBeginRendering vk_cmd_begin_rendering; -extern PFN_vkCmdEndRendering vk_cmd_end_rendering; -// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) - -} // namespace lt::renderer::vk diff --git a/modules/renderer/private/frontend/context/device.cpp b/modules/renderer/private/frontend/context/device.cpp deleted file mode 100644 index e8fc3a0..0000000 --- a/modules/renderer/private/frontend/context/device.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto IDevice::create(Api target_api, IGpu *gpu, ISurface *surface) - -> memory::Scope -{ - ensure(gpu, "Failed to create renderer::IDevice: null gpu"); - ensure(surface, "Failed to create renderer::IDevice: null surface"); - - switch (target_api) - { - case Api::vulkan: return memory::create_scope(gpu, surface); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} - -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/context/gpu.cpp b/modules/renderer/private/frontend/context/gpu.cpp deleted file mode 100644 index b9c120d..0000000 --- a/modules/renderer/private/frontend/context/gpu.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto IGpu::create(Api target_api, IInstance *instance) - -> memory::Scope -{ - switch (target_api) - { - case Api::vulkan: return memory::create_scope(instance); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} - -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/context/instance.cpp b/modules/renderer/private/frontend/context/instance.cpp deleted file mode 100644 index f8b6bc4..0000000 --- a/modules/renderer/private/frontend/context/instance.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto IInstance::get(Api target_api) -> IInstance * -{ - switch (target_api) - { - case Api::vulkan: return vk::Instance::get(); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} - -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/context/instance.test.cpp b/modules/renderer/private/frontend/context/instance.test.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/private/frontend/context/surface.cpp b/modules/renderer/private/frontend/context/surface.cpp deleted file mode 100644 index ef8447e..0000000 --- a/modules/renderer/private/frontend/context/surface.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto ISurface::create( - Api target_api, - IInstance *instance, - const ecs::Entity &surface_entity -) -> memory::Scope -{ - ensure(instance, "Failed to create renderer::ISurface: null instance"); - - switch (target_api) - { - case Api::vulkan: return memory::create_scope(instance, surface_entity); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} - -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/context/swapchain.cpp b/modules/renderer/private/frontend/context/swapchain.cpp deleted file mode 100644 index 33582cd..0000000 --- a/modules/renderer/private/frontend/context/swapchain.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto ISwapchain::create( - Api target_api, - ISurface *surface, - IGpu *gpu, - IDevice *device -) -> memory::Scope -{ - switch (target_api) - { - case Api::vulkan: return memory::create_scope(surface, gpu, device); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} - - -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/context/swapchain.test.cpp b/modules/renderer/private/frontend/context/swapchain.test.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/private/frontend/messenger.cpp b/modules/renderer/private/frontend/messenger.cpp deleted file mode 100644 index 9870c4d..0000000 --- a/modules/renderer/private/frontend/messenger.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -namespace lt::renderer { - -[[nodiscard]] /* static */ auto IMessenger::create( - Api target_api, - IInstance *instance, - CreateInfo info -) -> memory::Scope -{ - ensure( - info.severities != MessageSeverity::none, - "Failed to create vk::Messenger: severities == none" - ); - - ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none"); - - ensure(info.callback, "Failed to create vk::Messenger: null callback"); - - switch (target_api) - { - case Api::vulkan: return memory::create_scope(instance, std::move(info)); - case Api::none: - case Api::metal: - case Api::direct_x: throw std::runtime_error { "Invalid API" }; - } -} -} // namespace lt::renderer diff --git a/modules/renderer/private/frontend/messenger.test.cpp b/modules/renderer/private/frontend/messenger.test.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/private/test/constants.hpp b/modules/renderer/private/test/constants.hpp deleted file mode 100644 index 14755d9..0000000 --- a/modules/renderer/private/test/constants.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -namespace constants { - -}; diff --git a/modules/renderer/private/test/formatters.hpp b/modules/renderer/private/test/formatters.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/private/test/utils.cpp b/modules/renderer/private/test/utils.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/public/api.hpp b/modules/renderer/public/api.hpp deleted file mode 100644 index 373be79..0000000 --- a/modules/renderer/public/api.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -namespace lt::renderer { - -enum class Api : uint8_t -{ - none = 0, - - vulkan, - direct_x, - metal, -}; - -} diff --git a/modules/renderer/public/components/messenger.hpp b/modules/renderer/public/components/messenger.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/modules/renderer/public/components/skybox.hpp b/modules/renderer/public/components/skybox.hpp deleted file mode 100644 index 87e4ac7..0000000 --- a/modules/renderer/public/components/skybox.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -namespace lt::renderer { - -} // namespace lt::renderer diff --git a/modules/renderer/public/system.hpp b/modules/renderer/public/system.hpp deleted file mode 100644 index 18577cf..0000000 --- a/modules/renderer/public/system.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace lt::renderer { - -/** The main rendering engine. - * - * Responsible for: - * - Creating a rendering backend context (vk/dx/mt) - * - Connecting the context to the physical devices (select gpu, create surface, logical device) - * - Rendering the scene represented in registry via lt::renderer::components. - * - * @todo(Light): Add DirectX12 support - * @todo(Light): Add Metal support - */ -class System: public app::ISystem -{ -public: - /** config.max_frames_in_flight should not be higher than this value. */ - static constexpr auto frames_in_flight_upper_limit = 5u; - - /** config.max_frames_in_flight should not be lower than this value. */ - static constexpr auto frames_in_flight_lower_limit = 1u; - - struct Configuration - { - Api target_api; - - uint32_t max_frames_in_flight; - }; - - struct CreateInfo - { - Configuration config; - - memory::Ref registry; - - ecs::Entity surface_entity; - - IMessenger::CreateInfo debug_callback_info; - }; - - System(CreateInfo info); - - ~System() override; - - System(System &&) = default; - - System(const System &) = delete; - - auto operator=(System &&) -> System & = default; - - auto operator=(const System &) -> System & = delete; - - void on_register() override; - - void on_unregister() override; - - void tick(app::TickInfo tick) override; - - [[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override - { - return m_last_tick_result; - } - -private: - void handle_surface_resized_events(); - - void submit_scene(); - - void recreate_swapchain(); - - Api m_api; - - memory::Ref m_registry; - - ecs::Entity m_surface_entity; - - memory::Scope m_messenger; - - class IInstance *m_instance; - - memory::Scope m_surface; - - memory::Scope m_gpu; - - memory::Scope m_device; - - memory::Scope m_swapchain; - - memory::Scope m_renderer; - - app::TickResult m_last_tick_result {}; - - uint32_t m_frame_idx {}; - - uint32_t m_max_frames_in_flight {}; -}; - -} // namespace lt::renderer diff --git a/modules/renderer/private/system.cpp b/modules/renderer/system.cppm similarity index 61% rename from modules/renderer/private/system.cpp rename to modules/renderer/system.cppm index e550035..63b6baf 100644 --- a/modules/renderer/private/system.cpp +++ b/modules/renderer/system.cppm @@ -1,3 +1,114 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace lt::renderer { + +/** The main rendering engine. + * + * Responsible for: + * - Creating a rendering backend context (vk/dx/mt) + * - Connecting the context to the physical devices (select gpu, create surface, logical device) + * - Rendering the scene represented in registry via lt::renderer::components. + * + * @todo(Light): Add DirectX12 support + * @todo(Light): Add Metal support + */ +class System: public app::ISystem +{ +public: + /** config.max_frames_in_flight should not be higher than this value. */ + static constexpr auto frames_in_flight_upper_limit = 5u; + + /** config.max_frames_in_flight should not be lower than this value. */ + static constexpr auto frames_in_flight_lower_limit = 1u; + + struct Configuration + { + Api target_api; + + uint32_t max_frames_in_flight; + }; + + struct CreateInfo + { + Configuration config; + + memory::Ref registry; + + ecs::Entity surface_entity; + + IMessenger::CreateInfo debug_callback_info; + }; + + System(CreateInfo info); + + ~System() override; + + System(System &&) = default; + + System(const System &) = delete; + + auto operator=(System &&) -> System & = default; + + auto operator=(const System &) -> System & = delete; + + void on_register() override; + + void on_unregister() override; + + void tick(app::TickInfo tick) override; + + [[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override + { + return m_last_tick_result; + } + +private: + void handle_surface_resized_events(); + + void submit_scene(); + + void recreate_swapchain(); + + Api m_api; + + memory::Ref m_registry; + + ecs::Entity m_surface_entity; + + memory::Scope m_messenger; + + class IInstance *m_instance; + + memory::Scope m_surface; + + memory::Scope m_gpu; + + memory::Scope m_device; + + memory::Scope m_swapchain; + + memory::Scope m_renderer; + + app::TickResult m_last_tick_result {}; + + uint32_t m_frame_idx {}; + + uint32_t m_max_frames_in_flight {}; +}; + +} // namespace lt::renderer + +module :private; +using namespace lt::renderer; + #include #include #include @@ -14,8 +125,6 @@ #include #include -namespace lt::renderer { - System::System(CreateInfo info) : m_surface_entity(info.surface_entity) , m_api(info.config.target_api) @@ -124,5 +233,3 @@ void System::recreate_swapchain() m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get()); m_renderer->replace_swapchain(m_swapchain.get()); } - -} // namespace lt::renderer diff --git a/modules/renderer/private/system.test.cpp b/modules/renderer/system.test.cpp similarity index 100% rename from modules/renderer/private/system.test.cpp rename to modules/renderer/system.test.cpp diff --git a/modules/renderer/private/test/utils.hpp b/modules/renderer/test/utils.cppm similarity index 86% rename from modules/renderer/private/test/utils.hpp rename to modules/renderer/test/utils.cppm index ade724d..0cad1f4 100644 --- a/modules/renderer/private/test/utils.hpp +++ b/modules/renderer/test/utils.cppm @@ -1,29 +1,22 @@ -#pragma once +export module renderer.test_utils; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +export import logger; +export import surface.system; +export import test.test; +export import test.expects; +export import memory.reference; +export import renderer.frontend; -using ::lt::test::Case; -using ::lt::test::expect_eq; -using ::lt::test::expect_false; -using ::lt::test::expect_not_nullptr; -using ::lt::test::expect_throw; -using ::lt::test::expect_true; -using ::lt::test::Suite; -using ::std::ignore; +export using ::lt::test::Case; +export using ::lt::test::expect_eq; +export using ::lt::test::expect_false; +export using ::lt::test::expect_not_nullptr; +export using ::lt::test::expect_throw; +export using ::lt::test::expect_true; +export using ::lt::test::Suite; +export using ::std::ignore; -namespace constants { +export namespace constants { constexpr auto api = lt::renderer::Api::vulkan; constexpr auto resolution = lt::math::uvec2 { 800u, 600u }; @@ -32,7 +25,7 @@ constexpr auto frames_in_flight = uint32_t { 3u }; } // namespace constants -inline void noop_messenger_callback( +void noop_messenger_callback( lt::renderer::IMessenger::MessageSeverity severity, lt::renderer::IMessenger::MessageType type, const lt::renderer::IMessenger::MessageData &data, @@ -41,7 +34,7 @@ inline void noop_messenger_callback( { } -class Fixture_SurfaceSystem +export class Fixture_SurfaceSystem { public: Fixture_SurfaceSystem() @@ -96,7 +89,7 @@ private: lt::surface::System m_system = lt::surface::System(m_registry); }; -class Fixture_SurfaceGpu: public Fixture_SurfaceSystem +export class Fixture_SurfaceGpu: public Fixture_SurfaceSystem { public: Fixture_SurfaceGpu() = default; @@ -123,7 +116,7 @@ private: }; }; -class FixtureDeviceSwapchain: public Fixture_SurfaceGpu +export class FixtureDeviceSwapchain: public Fixture_SurfaceGpu { public: FixtureDeviceSwapchain() = default; @@ -209,7 +202,7 @@ private: }; }; -class Fixture_RendererSystem: public Fixture_SurfaceSystem +export class Fixture_RendererSystem: public Fixture_SurfaceSystem { public: Fixture_RendererSystem() = default;