diff --git a/src/editor/src/gui/drawStats.cpp b/src/editor/src/gui/drawStats.cpp index 4b80335..67cfa55 100644 --- a/src/editor/src/gui/drawStats.cpp +++ b/src/editor/src/gui/drawStats.cpp @@ -3,6 +3,7 @@ #include "core.hpp" #include "engine/buffers/Buffer.hpp" +#include "engine/literals/size.hpp" #include "safe_include.hpp" namespace fgl::engine::gui @@ -17,38 +18,37 @@ namespace fgl::engine::gui inline vk::DeviceSize free() const { return m_total - m_used; } - vk::DeviceSize m_largest_free_block; + vk::DeviceSize m_largest_free_block { std::numeric_limits< vk::DeviceSize >::max() }; }; AllocationInfo gpu {}; AllocationInfo host {}; }; - const AllocationList getTotalAllocated() + AllocationList getTotalAllocated() { AllocationList info {}; auto& [ gpu_allocated, gpu_used, gpu_largest_free ] = info.gpu; auto& [ host_allocated, host_used, host_largest_free ] = info.host; - for ( const std::weak_ptr< memory::BufferHandle >& buffer_weak : - fgl::engine::memory::Buffer::getActiveBufferHandles() ) + for ( const auto* buffer : memory::getActiveBuffers() ) { - if ( auto locked = buffer_weak.lock(); locked ) + // The buffer is still active. + if ( buffer->m_memory_properties & vk::MemoryPropertyFlagBits::eDeviceLocal ) { - // The buffer is still active. - if ( locked->m_memory_properties & vk::MemoryPropertyFlagBits::eDeviceLocal ) - { - gpu_allocated += locked->size(); - } - else if ( locked->m_memory_properties & vk::MemoryPropertyFlagBits::eHostVisible ) - { - host_allocated += locked->size(); - } - else - throw std:: - runtime_error( "Unknown memory property flag choice. Could not determine host vs device" ); + gpu_allocated += buffer->size(); + gpu_used += buffer->used(); + gpu_largest_free = std::min( buffer->largestBlock(), gpu_largest_free ); } + else if ( buffer->m_memory_properties & vk::MemoryPropertyFlagBits::eHostVisible ) + { + host_allocated += buffer->size(); + host_used += buffer->used(); + host_largest_free = std::min( buffer->largestBlock(), host_largest_free ); + } + else + throw std::runtime_error( "Unknown memory property flag choice. Could not determine host vs device" ); } return info; @@ -60,16 +60,20 @@ namespace fgl::engine::gui const auto& [ gpu_allocated, gpu_used, gpu_largest_block ] = gpu; const auto& [ host_allocated, host_used, host_largest_block ] = host; + using namespace literals::size_literals; + ImGui::Text( "Device" ); - ImGui::Text( "|- %0.1f MB Allocated", static_cast< float >( gpu_allocated ) / 1000.0f / 1000.0f ); - ImGui::Text( "|- %0.1f MB Used ", static_cast< float >( gpu_used ) / 1000.0f / 1000.0f ); - ImGui::Text( "|- %0.1f MB Unused", static_cast< float >( gpu.free() ) / 1000.0f / 1000.0f ); + ImGui::Text( "|- %s Allocated", to_string( gpu_allocated ).c_str() ); + ImGui::Text( "|- %s Used ", to_string( gpu_used ).c_str() ); + ImGui::Text( "|- %s Unused", to_string( gpu.free() ).c_str() ); + ImGui::Text( "|- %s Available in most allocated buffer", to_string( gpu.m_largest_free_block ).c_str() ); ImGui::Separator(); ImGui::Text( "Host" ); - ImGui::Text( "|- %0.1f MB Allocated", static_cast< float >( host_allocated ) / 1000.0f / 1000.0f ); - ImGui::Text( "|- %0.1f MB Used ", static_cast< float >( host_used ) / 1000.0f / 1000.0f ); - ImGui::Text( "|- %0.1f MB Unused", static_cast< float >( host.free() ) / 1000.0f / 1000.0f ); + ImGui::Text( "|- %s Allocated", to_string( host_allocated ).c_str() ); + ImGui::Text( "|- %s Used ", to_string( host_used ).c_str() ); + ImGui::Text( "|- %s Unused", to_string( host.free() ).c_str() ); + ImGui::Text( "|- %s Available in most allocated buffer", to_string( host.m_largest_free_block ).c_str() ); ImGui::Separator(); } diff --git a/src/engine/buffers/Buffer.cpp b/src/engine/buffers/Buffer.cpp index c255530..edffb36 100644 --- a/src/engine/buffers/Buffer.cpp +++ b/src/engine/buffers/Buffer.cpp @@ -12,34 +12,49 @@ namespace fgl::engine::memory { - BufferHandle::BufferHandle( - vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ) : + + inline static std::vector< Buffer* > active_buffers {}; + + std::vector< Buffer* > getActiveBuffers() + { + return active_buffers; + } + + Buffer:: + Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ) : m_memory_size( memory_size ), m_usage( usage ), m_memory_properties( memory_properties ) { alloc( memory_size ); + active_buffers.emplace_back( this ); + m_free_blocks.push_back( { 0, memory_size } ); } - BufferHandle::~BufferHandle() + Buffer::~Buffer() { + assert( this->m_allocations.size() == 0 ); dealloc(); + if ( auto itter = std::find( active_buffers.begin(), active_buffers.end(), this ); + itter != active_buffers.end() ) + active_buffers.erase( itter ); } - void* BufferHandle::map( BufferSuballocationHandle& handle ) + void* Buffer::map( BufferSuballocationHandle& handle ) { if ( m_alloc_info.pMappedData == nullptr ) return nullptr; return static_cast< std::byte* >( m_alloc_info.pMappedData ) + handle.m_offset; } - void BufferHandle::dealloc() + void Buffer::dealloc() { vmaDestroyBuffer( Device::getInstance().allocator(), m_buffer, m_allocation ); } - void BufferHandle::alloc( vk::DeviceSize memory_size ) + void Buffer::alloc( vk::DeviceSize memory_size ) { + assert( memory_size > 0 ); m_memory_size = memory_size; vk::BufferCreateInfo buffer_info {}; buffer_info.pNext = VK_NULL_HANDLE; @@ -79,25 +94,6 @@ namespace fgl::engine::memory vmaGetAllocationInfo( Device::getInstance().allocator(), m_allocation, &m_alloc_info ); } -#ifdef TRACK_BUFFERS - std::vector< std::weak_ptr< BufferHandle > > Buffer::getActiveBufferHandles() - { - std::vector< std::weak_ptr< BufferHandle > > handles; - handles.reserve( m_buffer_handles.size() ); - - for ( auto& handle : m_buffer_handles ) - { - if ( auto ptr = handle.lock() ) - { - handles.push_back( ptr ); - } - } - - m_buffer_handles = handles; - return handles; - } -#endif - vk::DeviceSize Buffer::alignment() { vk::DeviceSize size { 0 }; @@ -194,10 +190,9 @@ namespace fgl::engine::memory std::cout << "Total memory free: " << fgl::literals::size_literals::to_string( free_memory_counter ) << std::endl; - std::cout << "Total memory: " << fgl::literals::size_literals::to_string( m_handle->m_memory_size ) - << std::endl; + std::cout << "Total memory: " << fgl::literals::size_literals::to_string( m_memory_size ) << std::endl; - if ( allocated_memory_counter + free_memory_counter != m_handle->m_memory_size ) + if ( allocated_memory_counter + free_memory_counter != m_memory_size ) { std::cout << "Memory size mismatch detected! Difference of: " << ( allocated_memory_counter + free_memory_counter - memory_size ) << std::endl; @@ -303,7 +298,7 @@ namespace fgl::engine::memory vk::DebugUtilsObjectNameInfoEXT info {}; info.objectType = vk::ObjectType::eBuffer; info.pObjectName = str.c_str(); - info.objectHandle = reinterpret_cast< std::uint64_t >( static_cast< VkBuffer >( this->m_handle->m_buffer ) ); + info.objectHandle = reinterpret_cast< std::uint64_t >( static_cast< VkBuffer >( this->m_buffer ) ); Device::getInstance().setDebugUtilsObjectName( info ); } @@ -342,26 +337,27 @@ namespace fgl::engine::memory #endif } - void* Buffer::map( BufferSuballocationHandle& handle ) + vk::DeviceSize Buffer::used() const { - return this->m_handle->map( handle ); + vk::DeviceSize total_size { 0 }; + + if ( m_allocations.size() == 0 ) return total_size; + + for ( const auto& [ offset, size ] : m_allocations ) total_size += size; + + return total_size; } - Buffer:: - Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ) : - m_handle( std::make_shared< BufferHandle >( memory_size, usage, memory_properties ) ), - m_usage( usage ), - m_memory_properties( memory_properties ) + vk::DeviceSize Buffer::largestBlock() const { - m_free_blocks.insert( m_free_blocks.begin(), { 0, memory_size } ); -#ifdef TRACK_BUFFERS - m_buffer_handles.emplace_back( m_handle ); -#endif - } + vk::DeviceSize largest { 0 }; - Buffer::~Buffer() - { - assert( m_allocations.size() == 0 && "Buffer destructed while allocations still present" ); + for ( const auto& blocks : m_free_blocks ) + { + largest = std::max( largest, blocks.second ); + } + + return largest; } } // namespace fgl::engine::memory diff --git a/src/engine/buffers/Buffer.hpp b/src/engine/buffers/Buffer.hpp index a54c2cd..6b67657 100644 --- a/src/engine/buffers/Buffer.hpp +++ b/src/engine/buffers/Buffer.hpp @@ -20,12 +20,16 @@ namespace fgl::engine { class Device; -} + + namespace gui + { + struct AllocationList; + AllocationList getTotalAllocated(); + } // namespace gui +} // namespace fgl::engine namespace fgl::engine::memory { - - class BufferHandle; class BufferSuballocation; struct BufferSuballocationHandle; @@ -34,7 +38,7 @@ namespace fgl::engine::memory //TODO: Ensure this class can't be directly accessed from within Buffer unless we are trying // to access it in a debug manner (IE the drawStats menu) - struct BufferHandle + class Buffer { vk::Buffer m_buffer { VK_NULL_HANDLE }; VmaAllocation m_allocation {}; @@ -48,71 +52,33 @@ namespace fgl::engine::memory void alloc( vk::DeviceSize memory_size ); void dealloc(); - BufferHandle() = delete; - BufferHandle( const BufferHandle& other ) = delete; - BufferHandle& operator=( const BufferHandle& other ) = delete; - BufferHandle( BufferHandle&& other ) = delete; - BufferHandle& operator=( BufferHandle&& other ) = delete; + Buffer() = delete; + Buffer( const Buffer& other ) = delete; + Buffer& operator=( const Buffer& other ) = delete; + Buffer( Buffer&& other ) = delete; + Buffer& operator=( Buffer&& other ) = delete; - friend class Buffer; + public: - BufferHandle( - vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ); + Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ); - ~BufferHandle(); + ~Buffer(); auto address() const { return m_alloc_info.deviceMemory; } auto size() const { return m_alloc_info.size; } - void* map( BufferSuballocationHandle& handle ); - }; + vk::DeviceSize largestBlock() const; - class Buffer - { -#ifdef TRACK_BUFFERS - //! Tracking pointer for all buffers - inline static std::vector< std::weak_ptr< BufferHandle > > m_buffer_handles {}; - - public: - - static std::vector< std::weak_ptr< BufferHandle > > getActiveBufferHandles(); + vk::DeviceSize used() const; private: -#endif - - //TODO: Switch this to being a non pointer if we aren't tracking - // Since we don't need this to be a pointer at all if we don't need to track anything - // It'll just be wasted pointer dereferencing - std::shared_ptr< BufferHandle > m_handle; - - public: - - vk::BufferUsageFlags m_usage; - - vk::MemoryPropertyFlags m_memory_properties; - - Buffer() = delete; - Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ); - - ~Buffer(); - - Buffer( const Buffer& other ) = delete; - Buffer& operator=( const Buffer& other ) = delete; - - Buffer( Buffer&& other ) = default; - Buffer& operator=( Buffer&& other ) = default; - - inline vk::Buffer& getVkBuffer() noexcept { return m_handle->m_buffer; } + void* map( BufferSuballocationHandle& handle ); //! Returns the required alignment for this buffer. vk::DeviceSize alignment(); - std::shared_ptr< BufferHandle >& getHandle() { return m_handle; } - - private: - //! @brief List of all active suballocations //! std::map< vk::DeviceSize, vk::DeviceSize > m_allocations {}; @@ -125,40 +91,24 @@ namespace fgl::engine::memory public: //! Returns the vulkan buffer handle for this buffer - vk::Buffer getBuffer() const - { - assert( m_handle ); - assert( m_handle->m_buffer != VK_NULL_HANDLE ); - - return m_handle->m_buffer; - } + vk::Buffer getVkBuffer() const { return m_buffer; } //! Returns the vulkan memory handle for this buffer vk::DeviceMemory getMemory() const { - assert( m_handle ); - assert( m_handle->m_alloc_info.deviceMemory != VK_NULL_HANDLE ); + assert( m_alloc_info.deviceMemory != VK_NULL_HANDLE ); - return m_handle->m_alloc_info.deviceMemory; + return m_alloc_info.deviceMemory; } - //! Total memory size of the buffer - vk::DeviceSize size() const - { - assert( m_handle ); - assert( !std::isnan( m_handle->m_memory_size ) ); + friend struct BufferSuballocationHandle; + friend class BufferSuballocation; //TODO: Remove this - return m_handle->m_memory_size; - } + friend gui::AllocationList gui::getTotalAllocated(); - void* map( BufferSuballocationHandle& info ); + public: - bool isMappable() const - { - assert( m_handle ); - - return m_handle->m_alloc_info.pMappedData != nullptr; - } + bool isMappable() const { return m_alloc_info.pMappedData != nullptr; } //! Returns a allocation block from this buffer. Block will be aligned with nonUniformBufferOffsetAlignment //! and nonCoherentAtomSize if required (is_uniform_buffer and is_host_visible respectively) @@ -185,4 +135,5 @@ namespace fgl::engine::memory void setDebugName( const std::string str ); }; + std::vector< Buffer* > getActiveBuffers(); } // namespace fgl::engine::memory \ No newline at end of file diff --git a/src/engine/buffers/BufferSuballocation.hpp b/src/engine/buffers/BufferSuballocation.hpp index 96cb187..d7f4aed 100644 --- a/src/engine/buffers/BufferSuballocation.hpp +++ b/src/engine/buffers/BufferSuballocation.hpp @@ -10,7 +10,6 @@ namespace fgl::engine::memory { class Buffer; - class BufferHandle; class SuballocationView; struct BufferSuballocationHandle; diff --git a/src/engine/buffers/BufferSuballocationHandle.cpp b/src/engine/buffers/BufferSuballocationHandle.cpp index 4e34bfe..40cc8f0 100644 --- a/src/engine/buffers/BufferSuballocationHandle.cpp +++ b/src/engine/buffers/BufferSuballocationHandle.cpp @@ -12,7 +12,7 @@ namespace fgl::engine::memory { vk::Buffer BufferSuballocationHandle::getBuffer() { - return buffer.getBuffer(); + return buffer.getVkBuffer(); } BufferSuballocationHandle:: diff --git a/src/engine/buffers/BufferSuballocationHandle.hpp b/src/engine/buffers/BufferSuballocationHandle.hpp index 3b27f74..07cc0fa 100644 --- a/src/engine/buffers/BufferSuballocationHandle.hpp +++ b/src/engine/buffers/BufferSuballocationHandle.hpp @@ -6,6 +6,8 @@ #include +#include + namespace vk::raii { class CommandBuffer; diff --git a/src/engine/buffers/HostSingleT.hpp b/src/engine/buffers/HostSingleT.hpp index 59f36de..4932242 100644 --- a/src/engine/buffers/HostSingleT.hpp +++ b/src/engine/buffers/HostSingleT.hpp @@ -4,11 +4,14 @@ #pragma once -#include "Buffer.hpp" #include "BufferSuballocation.hpp" namespace fgl::engine { + namespace memory + { + class Buffer; + } //! Single element allocation of T template < typename T > diff --git a/src/engine/concepts/is_buffer.hpp b/src/engine/concepts/is_buffer.hpp index 029e5e8..0c5e379 100644 --- a/src/engine/concepts/is_buffer.hpp +++ b/src/engine/concepts/is_buffer.hpp @@ -2,17 +2,4 @@ // Created by kj16609 on 12/29/23. // -#pragma once - -#include - -#include "engine/buffers/Buffer.hpp" - -namespace fgl::engine::memory -{ - template < typename T > concept is_buffer = std::same_as< T, Buffer >; - - template < typename T > - concept is_buffer_ref = std::is_reference_v< T > && is_buffer< std::remove_reference_t< T > >; - -} // namespace fgl::engine::memory \ No newline at end of file +#pragma once \ No newline at end of file diff --git a/src/engine/concepts/is_suballocation.hpp b/src/engine/concepts/is_suballocation.hpp index 3090929..ae12540 100644 --- a/src/engine/concepts/is_suballocation.hpp +++ b/src/engine/concepts/is_suballocation.hpp @@ -4,29 +4,18 @@ #pragma once -#include "is_buffer.hpp" - namespace fgl::engine::memory { template < typename T > - concept is_suballocation = requires( T t ) { - { - t.getBuffer() - } -> is_buffer_ref; - { - t.getVkBuffer() - } -> std::same_as< vk::Buffer >; - { - t.getOffset() - } -> std::same_as< vk::DeviceSize >; + concept is_suballocation = requires( const T t ) { + { t.getVkBuffer() } -> std::same_as< vk::Buffer >; + { t.getOffset() } -> std::same_as< vk::DeviceSize >; /* { t.size() } -> std::same_as< vk::DeviceSize >; */ - { - t.descriptorInfo() - } -> std::same_as< vk::DescriptorBufferInfo >; + { t.descriptorInfo() } -> std::same_as< vk::DescriptorBufferInfo >; }; } // namespace fgl::engine::memory \ No newline at end of file