feat(renderer): storage & staging buffer types
	
		
			
	
		
	
	
		
	
		
			Some checks reported errors
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build was killed
				
			
		
		
	
	
				
					
				
			
		
			Some checks reported errors
		
		
	
	continuous-integration/drone/push Build was killed
				
			This commit is contained in:
		
							parent
							
								
									2ddb90faff
								
							
						
					
					
						commit
						5422792705
					
				
					 5 changed files with 101 additions and 34 deletions
				
			
		|  | @ -16,7 +16,7 @@ Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info) | |||
|               .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | ||||
|           } | ||||
|       ) | ||||
|     , m_memory(m_device, m_buffer, allocation_info_from_memory_requirements()) | ||||
|     , m_memory(m_device, m_buffer, determine_allocation_info(info.usage)) | ||||
|     , m_size(info.size) | ||||
| { | ||||
| } | ||||
|  | @ -31,30 +31,18 @@ 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 | ||||
| [[nodiscard]] auto Buffer::determine_allocation_info(Usage usage) 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; | ||||
| 	const auto required_properties = to_native_memory_properties(usage); | ||||
| 	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)) | ||||
| 		const auto property_flags = memory_properties.memoryTypes[idx].propertyFlags; | ||||
| 		if (has_correct_memory_type_bit(requirements.memoryTypeBits, idx) | ||||
| 		    && has_required_memory_properties(required_properties, property_flags)) | ||||
| 
 | ||||
| 		{ | ||||
| 			type = idx; | ||||
|  | @ -69,4 +57,50 @@ void Buffer::unmap() /* override */ | |||
| 	}; | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags | ||||
| { | ||||
| 	switch (usage) | ||||
| 	{ | ||||
| 	case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; | ||||
| 
 | ||||
| 	case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; | ||||
| 
 | ||||
| 	case Usage::storage: | ||||
| 		return VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; | ||||
| 
 | ||||
| 	case Usage::staging: return VK_BUFFER_USAGE_TRANSFER_SRC_BIT; | ||||
| 	} | ||||
| 
 | ||||
| 	std::unreachable(); | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] auto Buffer::to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags | ||||
| { | ||||
| 	switch (usage) | ||||
| 	{ | ||||
| 	case Usage::vertex: | ||||
| 	case Usage::index: | ||||
| 	case Usage::storage: return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; | ||||
| 
 | ||||
| 	case Usage::staging: | ||||
| 		return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | ||||
| 	} | ||||
| 
 | ||||
| 	std::unreachable(); | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] auto Buffer::has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const | ||||
|     -> bool | ||||
| { | ||||
| 	return type_bits & (1 << type_idx); | ||||
| } | ||||
| 
 | ||||
| [[nodiscard]] auto Buffer::has_required_memory_properties( | ||||
|     uint32_t required_properties, | ||||
|     uint32_t property_flags | ||||
| ) const -> bool | ||||
| { | ||||
| 	return (property_flags & required_properties) == required_properties; | ||||
| } | ||||
| 
 | ||||
| } // namespace lt::renderer::vk
 | ||||
|  |  | |||
|  | @ -14,15 +14,36 @@ public: | |||
| 
 | ||||
| 	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 allocation_info_from_memory_requirements() const -> VkMemoryAllocateInfo; | ||||
| 	[[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 {}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,3 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <renderer/backend/vk/data/buffer.hpp> | ||||
| #include <renderer/frontend/data/buffer.hpp> | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,11 +8,15 @@ namespace lt::renderer { | |||
| class IBuffer | ||||
| { | ||||
| public: | ||||
| 	enum Usage : uint8_t | ||||
| 	enum class Usage : uint8_t | ||||
| 	{ | ||||
| 		vertex, | ||||
| 
 | ||||
| 		index, | ||||
| 
 | ||||
| 		storage, | ||||
| 
 | ||||
| 		staging, | ||||
| 	}; | ||||
| 
 | ||||
| 	struct CreateInfo | ||||
|  | @ -24,6 +28,13 @@ public: | |||
| 		std::string debug_name; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct CopyInfo | ||||
| 	{ | ||||
| 		size_t offset; | ||||
| 
 | ||||
| 		size_t size; | ||||
| 	}; | ||||
| 
 | ||||
| 	[[nodiscard]] static auto create( | ||||
| 	    Api target_api, | ||||
| 	    class IDevice *device, | ||||
|  |  | |||
|  | @ -8,16 +8,19 @@ 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 = "", | ||||
| 		    } | ||||
| 		); | ||||
| 		for (auto idx = 0; idx <= std::to_underlying(IBuffer::Usage::staging); ++idx) | ||||
| 		{ | ||||
| 			ignore = IBuffer::create( | ||||
| 			    lt::renderer::Api::vulkan, | ||||
| 			    fixture.device(), | ||||
| 			    fixture.gpu(), | ||||
| 			    IBuffer::CreateInfo { | ||||
| 			        .usage = static_cast<IBuffer::Usage>(idx), | ||||
| 			        .size = 1000u, | ||||
| 			        .debug_name = "", | ||||
| 			    } | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		expect_false(fixture.has_any_messages_of(error)); | ||||
| 		expect_false(fixture.has_any_messages_of(warning)); | ||||
|  | @ -77,7 +80,7 @@ Suite raii = "buffer_raii"_suite = [] { | |||
| 			); | ||||
| 		}); | ||||
| 
 | ||||
| 		/** Make sure the default-case was good */ | ||||
| 		/** Make sure the default-case was OK */ | ||||
| 		ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), fixture.gpu(), info); | ||||
| 
 | ||||
| 		expect_false(fixture.has_any_messages_of(error)); | ||||
|  | @ -96,7 +99,7 @@ Suite mapping = "buffer_mapping"_suite = [] { | |||
| 		    fixture.device(), | ||||
| 		    fixture.gpu(), | ||||
| 		    IBuffer::CreateInfo { | ||||
| 		        .usage = IBuffer::Usage::vertex, | ||||
| 		        .usage = IBuffer::Usage::staging, | ||||
| 		        .size = size, | ||||
| 		        .debug_name = "", | ||||
| 		    } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue