feat(renderer): buffer #61
					 17 changed files with 493 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -8,15 +8,17 @@ add_library_module(
 | 
			
		|||
    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
 | 
			
		||||
    # Vulkan - frontend
 | 
			
		||||
    # 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)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,11 +36,10 @@ add_test_module(
 | 
			
		|||
    frontend/context/surface.test.cpp
 | 
			
		||||
    frontend/context/device.test.cpp
 | 
			
		||||
    frontend/context/swapchain.test.cpp
 | 
			
		||||
    frontend/data/buffer.test.cpp
 | 
			
		||||
    frontend/renderer/pass.test.cpp
 | 
			
		||||
    frontend/renderer/renderer.test.cpp
 | 
			
		||||
    # backend specific tests -- vk
 | 
			
		||||
    backend/vk/context/instance.test.cpp
 | 
			
		||||
    # backend specific tests -- dx backend specific tests -- mt
 | 
			
		||||
)
 | 
			
		||||
    backend/vk/context/instance.test.cpp)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(renderer_tests PRIVATE surface pthread)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -207,6 +207,31 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
 | 
			
		|||
	return images;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements
 | 
			
		||||
{
 | 
			
		||||
	auto requirements = VkMemoryRequirements {};
 | 
			
		||||
	vk_get_buffer_memory_requirements(m_device, buffer, &requirements);
 | 
			
		||||
	return requirements;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Device::bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset /* = 0u */) const
 | 
			
		||||
{
 | 
			
		||||
	vkc(vk_bind_buffer_memory(m_device, buffer, memory, offset));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
 | 
			
		||||
    -> std::span<std::byte>
 | 
			
		||||
{
 | 
			
		||||
	void *data = {};
 | 
			
		||||
	vkc(vk_map_memory(m_device, memory, offset, size, {}, &data));
 | 
			
		||||
	return { std::bit_cast<std::byte *>(data), size };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Device::unmap_memory(VkDeviceMemory memory)
 | 
			
		||||
{
 | 
			
		||||
	vk_unmap_memory(m_device, memory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR
 | 
			
		||||
{
 | 
			
		||||
	auto *swapchain = VkSwapchainKHR {};
 | 
			
		||||
| 
						 | 
				
			
			@ -299,6 +324,13 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
 | 
			
		|||
	return fences;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::create_buffer(VkBufferCreateInfo info) const -> VkBuffer
 | 
			
		||||
{
 | 
			
		||||
	auto *buffer = VkBuffer {};
 | 
			
		||||
	vkc(vk_create_buffer(m_device, &info, nullptr, &buffer));
 | 
			
		||||
	return buffer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::allocate_command_buffers(VkCommandBufferAllocateInfo info) const
 | 
			
		||||
    -> std::vector<VkCommandBuffer>
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -307,6 +339,18 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
 | 
			
		|||
	return command_buffers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Device::allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory
 | 
			
		||||
{
 | 
			
		||||
	auto *memory = VkDeviceMemory {};
 | 
			
		||||
	vkc(vk_allocate_memory(m_device, &info, nullptr, &memory));
 | 
			
		||||
	return memory;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Device::free_memory(VkDeviceMemory memory) const
 | 
			
		||||
{
 | 
			
		||||
	vk_free_memory(m_device, memory, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Device::destroy_swapchain(VkSwapchainKHR swapchain) const
 | 
			
		||||
{
 | 
			
		||||
	vk_destroy_swapchain_khr(m_device, swapchain, m_allocator);
 | 
			
		||||
| 
						 | 
				
			
			@ -389,4 +433,9 @@ void Device::destroy_fences(std::span<VkFence> fences) const
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Device::destroy_buffer(VkBuffer buffer) const
 | 
			
		||||
{
 | 
			
		||||
	vk_destroy_buffer(m_device, buffer, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace lt::renderer::vk
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,16 @@ public:
 | 
			
		|||
 | 
			
		||||
	[[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector<VkImage>;
 | 
			
		||||
 | 
			
		||||
	[[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<std::byte>;
 | 
			
		||||
 | 
			
		||||
	void unmap_memory(VkDeviceMemory memory);
 | 
			
		||||
 | 
			
		||||
	/** create functions */
 | 
			
		||||
	[[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -120,10 +130,17 @@ public:
 | 
			
		|||
	[[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const
 | 
			
		||||
	    -> std::vector<VkFence>;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
 | 
			
		||||
 | 
			
		||||
	/** allocation functions */
 | 
			
		||||
	[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
 | 
			
		||||
	    -> std::vector<VkCommandBuffer>;
 | 
			
		||||
 | 
			
		||||
	/** de-allocation functions */
 | 
			
		||||
	void free_memory(VkDeviceMemory memory) const;
 | 
			
		||||
 | 
			
		||||
	/** destroy functions */
 | 
			
		||||
	void destroy_swapchain(VkSwapchainKHR swapchain) const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +170,8 @@ public:
 | 
			
		|||
 | 
			
		||||
	void destroy_fences(std::span<VkFence> fences) const;
 | 
			
		||||
 | 
			
		||||
	void destroy_buffer(VkBuffer buffer) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	template<typename T>
 | 
			
		||||
	static auto get_object_type(const T &object) -> VkObjectType
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,5 +67,11 @@ Gpu::Gpu(IInstance *instance)
 | 
			
		|||
	return formats;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Gpu::get_memory_properties() const -> VkPhysicalDeviceMemoryProperties
 | 
			
		||||
{
 | 
			
		||||
	auto memory_properties = VkPhysicalDeviceMemoryProperties {};
 | 
			
		||||
	vk_get_physical_device_memory_properties(m_gpu, &memory_properties);
 | 
			
		||||
	return memory_properties;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace lt::renderer::vk
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,8 @@ public:
 | 
			
		|||
	[[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const
 | 
			
		||||
	    -> std::vector<VkSurfaceFormatKHR>;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	memory::NullOnMove<VkPhysicalDevice> m_gpu = VK_NULL_HANDLE;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ PFN_vkGetDeviceProcAddr vk_get_device_proc_address {};
 | 
			
		|||
PFN_vkDestroyDevice vk_destroy_device {};
 | 
			
		||||
PFN_vkGetPhysicalDeviceFeatures 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 {};
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +88,16 @@ PFN_vkCmdDraw vk_cmd_draw {};
 | 
			
		|||
PFN_vkCmdSetViewport vk_cmd_set_viewport {};
 | 
			
		||||
PFN_vkCmdSetScissor vk_cmd_set_scissors {};
 | 
			
		||||
 | 
			
		||||
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_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
 | 
			
		||||
| 
						 | 
				
			
			@ -298,6 +309,7 @@ void Instance::load_instance_functions()
 | 
			
		|||
	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");
 | 
			
		||||
| 
						 | 
				
			
			@ -370,6 +382,14 @@ void Instance::load_device_functions_impl(VkDevice device)
 | 
			
		|||
	load_fn(vk_cmd_draw, "vkCmdDraw");
 | 
			
		||||
	load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
 | 
			
		||||
	load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
 | 
			
		||||
	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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										72
									
								
								modules/renderer/private/backend/vk/data/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								modules/renderer/private/backend/vk/data/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
#include <renderer/backend/vk/context/device.hpp>
 | 
			
		||||
#include <renderer/backend/vk/context/gpu.hpp>
 | 
			
		||||
#include <renderer/backend/vk/data/buffer.hpp>
 | 
			
		||||
 | 
			
		||||
namespace lt::renderer::vk {
 | 
			
		||||
 | 
			
		||||
Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info)
 | 
			
		||||
    : m_device(static_cast<Device *>(device))
 | 
			
		||||
    , m_gpu(static_cast<Gpu *>(gpu))
 | 
			
		||||
    , m_buffer(
 | 
			
		||||
          m_device,
 | 
			
		||||
          VkBufferCreateInfo {
 | 
			
		||||
              .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
 | 
			
		||||
              .size = info.size,
 | 
			
		||||
              .usage = to_native_usage_flags(info.usage),
 | 
			
		||||
              .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
 | 
			
		||||
          }
 | 
			
		||||
      )
 | 
			
		||||
    , m_memory(m_device, m_buffer, allocation_info_from_memory_requirements())
 | 
			
		||||
    , m_size(info.size)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Buffer::map() -> std::span<std::byte> /* override */
 | 
			
		||||
{
 | 
			
		||||
	return m_device->map_memory(m_memory, m_size, 0ul);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Buffer::unmap() /* override */
 | 
			
		||||
{
 | 
			
		||||
	m_device->unmap_memory(m_memory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags
 | 
			
		||||
{
 | 
			
		||||
	switch (usage)
 | 
			
		||||
	{
 | 
			
		||||
	case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
 | 
			
		||||
	case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::unreachable();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] auto Buffer::allocation_info_from_memory_requirements() const -> VkMemoryAllocateInfo
 | 
			
		||||
{
 | 
			
		||||
	const auto requirements = m_device->get_memory_requirements(m_buffer);
 | 
			
		||||
	auto memory_properties = m_gpu->get_memory_properties();
 | 
			
		||||
 | 
			
		||||
	const auto required_properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
 | 
			
		||||
	                                 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
 | 
			
		||||
	auto type = 0u;
 | 
			
		||||
	for (auto idx = 0; idx < memory_properties.memoryTypeCount; ++idx)
 | 
			
		||||
	{
 | 
			
		||||
		if ((requirements.memoryTypeBits & (1 << idx))
 | 
			
		||||
		    && ((memory_properties.memoryTypes[idx].propertyFlags & required_properties)
 | 
			
		||||
		        == required_properties))
 | 
			
		||||
 | 
			
		||||
		{
 | 
			
		||||
			type = idx;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return VkMemoryAllocateInfo {
 | 
			
		||||
		.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
 | 
			
		||||
		.allocationSize = requirements.size,
 | 
			
		||||
		.memoryTypeIndex = type,
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace lt::renderer::vk
 | 
			
		||||
							
								
								
									
										39
									
								
								modules/renderer/private/backend/vk/data/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								modules/renderer/private/backend/vk/data/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <renderer/backend/vk/raii/raii.hpp>
 | 
			
		||||
#include <renderer/frontend/data/buffer.hpp>
 | 
			
		||||
 | 
			
		||||
namespace lt::renderer::vk {
 | 
			
		||||
 | 
			
		||||
class Buffer: public IBuffer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto map() -> std::span<std::byte> override;
 | 
			
		||||
 | 
			
		||||
	void unmap() override;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto get_size() const -> size_t override
 | 
			
		||||
	{
 | 
			
		||||
		return m_size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto allocation_info_from_memory_requirements() const -> VkMemoryAllocateInfo;
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
#include <memory/pointer_types/null_on_move.hpp>
 | 
			
		||||
#include <renderer/backend/vk/context/device.hpp>
 | 
			
		||||
#include <renderer/backend/vk/context/instance.hpp>
 | 
			
		||||
#include <renderer/backend/vk/vulkan.hpp>
 | 
			
		||||
 | 
			
		||||
namespace lt::renderer::vk::raii {
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
 | 
			
		||||
namespace lt::renderer::vk::raii { // NOLINTBEGIN(cppcoreguidelines-special-member-functions)
 | 
			
		||||
 | 
			
		||||
class DebugMessenger
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -16,12 +17,10 @@ public:
 | 
			
		|||
 | 
			
		||||
	~DebugMessenger()
 | 
			
		||||
	{
 | 
			
		||||
		if (!m_instance)
 | 
			
		||||
		if (m_instance)
 | 
			
		||||
		{
 | 
			
		||||
			return;
 | 
			
		||||
			m_instance->destroy_messenger(m_object);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m_instance->destroy_messenger(m_object);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
| 
						 | 
				
			
			@ -30,4 +29,74 @@ private:
 | 
			
		|||
	VkDebugUtilsMessengerEXT m_object;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
 | 
			
		||||
class Buffer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Buffer(Device *device, VkBufferCreateInfo info)
 | 
			
		||||
	    : m_device(device)
 | 
			
		||||
	    , m_object(m_device->create_buffer(info))
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~Buffer()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_device)
 | 
			
		||||
		{
 | 
			
		||||
			m_device->destroy_buffer(m_object);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto operator*() const -> VkBuffer
 | 
			
		||||
	{
 | 
			
		||||
		return m_object;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] operator VkBuffer() const
 | 
			
		||||
	{
 | 
			
		||||
		return m_object;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	memory::NullOnMove<Device *> m_device {};
 | 
			
		||||
 | 
			
		||||
	VkBuffer m_object;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Memory
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Memory(Device *device, VkBuffer buffer, VkMemoryAllocateInfo info)
 | 
			
		||||
	    : m_device(device)
 | 
			
		||||
	    , m_object(m_device->allocate_memory(info))
 | 
			
		||||
	{
 | 
			
		||||
		m_device->bind_memory(buffer, m_object);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~Memory()
 | 
			
		||||
	{
 | 
			
		||||
		if (m_device)
 | 
			
		||||
		{
 | 
			
		||||
			m_device->free_memory(m_object);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto operator*() const -> VkDeviceMemory
 | 
			
		||||
	{
 | 
			
		||||
		return m_object;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] operator VkDeviceMemory() const
 | 
			
		||||
	{
 | 
			
		||||
		return m_object;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	memory::NullOnMove<Device *> m_device {};
 | 
			
		||||
 | 
			
		||||
	VkDeviceMemory m_object = VK_NULL_HANDLE;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// NOLINTEND(cppcoreguidelines-special-member-functions)
 | 
			
		||||
} // namespace lt::renderer::vk::raii
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,18 +0,0 @@
 | 
			
		|||
// template<>
 | 
			
		||||
// struct std::formatter<VkExtent2D>
 | 
			
		||||
// {
 | 
			
		||||
// 	constexpr auto parse(std::format_parse_context &context)
 | 
			
		||||
// 	{
 | 
			
		||||
// 		return context.begin();
 | 
			
		||||
// 	}
 | 
			
		||||
//
 | 
			
		||||
// 	auto format(const VkExtent2D &val, std::format_context &context) const
 | 
			
		||||
// 	{
 | 
			
		||||
// 		return std::format_to(context.out(), "{}, {}", val.width, val.height);
 | 
			
		||||
// 	}
 | 
			
		||||
// };
 | 
			
		||||
//
 | 
			
		||||
// inline auto operator==(VkExtent2D lhs, VkExtent2D rhs) -> bool
 | 
			
		||||
// {
 | 
			
		||||
// 	return lhs.width == rhs.width && lhs.height == rhs.height;
 | 
			
		||||
// }
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
 | 
			
		|||
extern PFN_vkDestroyDevice vk_destroy_device;
 | 
			
		||||
extern PFN_vkGetPhysicalDeviceFeatures 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +77,15 @@ extern PFN_vkCmdDraw vk_cmd_draw;
 | 
			
		|||
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
 | 
			
		||||
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								modules/renderer/private/frontend/data/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								modules/renderer/private/frontend/data/buffer.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <renderer/backend/vk/data/buffer.hpp>
 | 
			
		||||
#include <renderer/frontend/data/buffer.hpp>
 | 
			
		||||
 | 
			
		||||
namespace lt::renderer {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[[nodiscard]] /* static */ auto IBuffer::create(
 | 
			
		||||
    Api target_api,
 | 
			
		||||
    class IDevice *device,
 | 
			
		||||
    class IGpu *gpu,
 | 
			
		||||
    const CreateInfo &info
 | 
			
		||||
) -> memory::Scope<IBuffer>
 | 
			
		||||
{
 | 
			
		||||
	ensure(device, "Failed to create renderer::IBuffer: null device");
 | 
			
		||||
	ensure(gpu, "Failed to create renderer::IBuffer: null gpu");
 | 
			
		||||
	ensure(info.size > 0, "Failed to create renderer::IBuffer: null size");
 | 
			
		||||
 | 
			
		||||
	switch (target_api)
 | 
			
		||||
	{
 | 
			
		||||
	case Api::vulkan: return memory::create_scope<vk::Buffer>(device, gpu, info);
 | 
			
		||||
	case Api::none:
 | 
			
		||||
	case Api::metal:
 | 
			
		||||
	case Api::direct_x: throw std::runtime_error { "Invalid API" };
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace lt::renderer
 | 
			
		||||
							
								
								
									
										55
									
								
								modules/renderer/private/frontend/data/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								modules/renderer/private/frontend/data/buffer.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory/scope.hpp>
 | 
			
		||||
#include <renderer/api.hpp>
 | 
			
		||||
 | 
			
		||||
namespace lt::renderer {
 | 
			
		||||
 | 
			
		||||
class IBuffer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	enum Usage : uint8_t
 | 
			
		||||
	{
 | 
			
		||||
		vertex,
 | 
			
		||||
 | 
			
		||||
		index,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	struct CreateInfo
 | 
			
		||||
	{
 | 
			
		||||
		Usage usage;
 | 
			
		||||
 | 
			
		||||
		size_t size;
 | 
			
		||||
 | 
			
		||||
		std::string debug_name;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] static auto create(
 | 
			
		||||
	    Api target_api,
 | 
			
		||||
	    class IDevice *device,
 | 
			
		||||
	    class IGpu *gpu,
 | 
			
		||||
	    const CreateInfo &info
 | 
			
		||||
	) -> memory::Scope<IBuffer>;
 | 
			
		||||
 | 
			
		||||
	IBuffer() = default;
 | 
			
		||||
 | 
			
		||||
	virtual ~IBuffer() = default;
 | 
			
		||||
 | 
			
		||||
	IBuffer(IBuffer &&) = default;
 | 
			
		||||
 | 
			
		||||
	IBuffer(const IBuffer &) = delete;
 | 
			
		||||
 | 
			
		||||
	auto operator=(IBuffer &&) -> IBuffer & = default;
 | 
			
		||||
 | 
			
		||||
	auto operator=(const IBuffer &) -> IBuffer & = delete;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] virtual auto map() -> std::span<std::byte> = 0;
 | 
			
		||||
 | 
			
		||||
	virtual void unmap() = 0;
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] virtual auto get_size() const -> size_t = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace lt::renderer
 | 
			
		||||
							
								
								
									
										112
									
								
								modules/renderer/private/frontend/data/buffer.test.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								modules/renderer/private/frontend/data/buffer.test.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,112 @@
 | 
			
		|||
#include <renderer/frontend/data/buffer.hpp>
 | 
			
		||||
#include <renderer/test/utils.hpp>
 | 
			
		||||
 | 
			
		||||
using ::lt::renderer::IBuffer;
 | 
			
		||||
using enum ::lt::renderer::IMessenger::MessageSeverity;
 | 
			
		||||
 | 
			
		||||
Suite raii = "buffer_raii"_suite = [] {
 | 
			
		||||
	Case { "happy path won't throw" } = [] {
 | 
			
		||||
		auto fixture = FixtureDeviceSwapchain {};
 | 
			
		||||
 | 
			
		||||
		ignore = IBuffer::create(
 | 
			
		||||
		    lt::renderer::Api::vulkan,
 | 
			
		||||
		    fixture.device(),
 | 
			
		||||
		    fixture.gpu(),
 | 
			
		||||
		    IBuffer::CreateInfo {
 | 
			
		||||
		        .usage = IBuffer::Usage::vertex,
 | 
			
		||||
		        .size = 1000u,
 | 
			
		||||
		        .debug_name = "",
 | 
			
		||||
		    }
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(error));
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(warning));
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Case { "unhappy path throws" } = [] {
 | 
			
		||||
		auto fixture = FixtureDeviceSwapchain {};
 | 
			
		||||
 | 
			
		||||
		auto info = IBuffer::CreateInfo {
 | 
			
		||||
			.usage = IBuffer::Usage::vertex,
 | 
			
		||||
			.size = 10000u,
 | 
			
		||||
			.debug_name = "",
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		expect_throw([&] {
 | 
			
		||||
			ignore = IBuffer::create(lt::renderer::Api::vulkan, nullptr, fixture.gpu(), info);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		expect_throw([&] {
 | 
			
		||||
			ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), nullptr, info);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		expect_throw([&, info] mutable {
 | 
			
		||||
			info.size = 0;
 | 
			
		||||
			ignore = IBuffer::create(
 | 
			
		||||
			    lt::renderer::Api::vulkan,
 | 
			
		||||
			    fixture.device(),
 | 
			
		||||
			    fixture.gpu(),
 | 
			
		||||
			    info
 | 
			
		||||
			);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		expect_throw([&] {
 | 
			
		||||
			ignore = IBuffer::create(
 | 
			
		||||
			    lt::renderer::Api::direct_x,
 | 
			
		||||
			    fixture.device(),
 | 
			
		||||
			    fixture.gpu(),
 | 
			
		||||
			    info
 | 
			
		||||
			);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		expect_throw([&] {
 | 
			
		||||
			ignore = IBuffer::create(
 | 
			
		||||
			    lt::renderer::Api::metal,
 | 
			
		||||
			    fixture.device(),
 | 
			
		||||
			    fixture.gpu(),
 | 
			
		||||
			    info
 | 
			
		||||
			);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		expect_throw([&] {
 | 
			
		||||
			ignore = IBuffer::create(
 | 
			
		||||
			    lt::renderer::Api::none,
 | 
			
		||||
			    fixture.device(),
 | 
			
		||||
			    fixture.gpu(),
 | 
			
		||||
			    info
 | 
			
		||||
			);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		/** Make sure the default-case was good */
 | 
			
		||||
		ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), fixture.gpu(), info);
 | 
			
		||||
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(error));
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(warning));
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Suite mapping = "buffer_mapping"_suite = [] {
 | 
			
		||||
	Case { "mapping" } = [] {
 | 
			
		||||
		auto fixture = FixtureDeviceSwapchain {};
 | 
			
		||||
 | 
			
		||||
		constexpr auto size = 1000u;
 | 
			
		||||
 | 
			
		||||
		auto buffer = IBuffer::create(
 | 
			
		||||
		    lt::renderer::Api::vulkan,
 | 
			
		||||
		    fixture.device(),
 | 
			
		||||
		    fixture.gpu(),
 | 
			
		||||
		    IBuffer::CreateInfo {
 | 
			
		||||
		        .usage = IBuffer::Usage::vertex,
 | 
			
		||||
		        .size = size,
 | 
			
		||||
		        .debug_name = "",
 | 
			
		||||
		    }
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		auto map = buffer->map();
 | 
			
		||||
		expect_eq(map.size(), size);
 | 
			
		||||
		expect_not_nullptr(map.data());
 | 
			
		||||
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(error));
 | 
			
		||||
		expect_false(fixture.has_any_messages_of(warning));
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +148,6 @@ public:
 | 
			
		|||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] auto has_any_messages() const -> bool
 | 
			
		||||
	{
 | 
			
		||||
		return m_user_data->m_has_any_messages;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@
 | 
			
		|||
 | 
			
		||||
namespace lt::renderer {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IMessenger
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue