Add memory buffer allocation count into the stats screen
This commit is contained in:
@@ -1,16 +1,89 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "core.hpp"
|
||||
#include "engine/buffers/Buffer.hpp"
|
||||
#include "safe_include.hpp"
|
||||
|
||||
namespace fgl::engine::gui
|
||||
{
|
||||
|
||||
struct AllocationList
|
||||
{
|
||||
struct AllocationInfo
|
||||
{
|
||||
vk::DeviceSize m_total;
|
||||
vk::DeviceSize m_used;
|
||||
|
||||
inline vk::DeviceSize free() const { return m_total - m_used; }
|
||||
|
||||
vk::DeviceSize m_largest_free_block;
|
||||
};
|
||||
|
||||
AllocationInfo gpu {};
|
||||
AllocationInfo host {};
|
||||
};
|
||||
|
||||
const 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() )
|
||||
{
|
||||
if ( auto locked = buffer_weak.lock(); locked )
|
||||
{
|
||||
// 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" );
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
void drawMemoryStats()
|
||||
{
|
||||
const auto [ gpu, host ] = getTotalAllocated();
|
||||
const auto& [ gpu_allocated, gpu_used, gpu_largest_block ] = gpu;
|
||||
const auto& [ host_allocated, host_used, host_largest_block ] = host;
|
||||
|
||||
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::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::Separator();
|
||||
}
|
||||
|
||||
void drawStats( const FrameInfo& info )
|
||||
{
|
||||
ImGui::Begin( "Stats" );
|
||||
|
||||
ImGui::Text( "FPS: %0.1f", ImGui::GetIO().Framerate );
|
||||
|
||||
if ( ImGui::CollapsingHeader( "Memory" ) )
|
||||
{
|
||||
drawMemoryStats();
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,10 @@ else ()
|
||||
target_compile_definitions(FGLEngine PUBLIC FGL_TESTS=0)
|
||||
endif ()
|
||||
|
||||
# Enable tracking for buffers, I need to find some way to disable this when trying to link
|
||||
# with the game itself
|
||||
target_compile_definitions(FGLEngine PUBLIC TRACK_BUFFERS)
|
||||
|
||||
|
||||
#GLM settings
|
||||
# GLM_FORCE_NO_CTOR_INIT
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "Buffer.hpp"
|
||||
|
||||
#include "BufferSuballocationHandle.hpp"
|
||||
#include "align.hpp"
|
||||
#include "engine/buffers/exceptions.hpp"
|
||||
@@ -78,6 +79,7 @@ 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;
|
||||
@@ -94,6 +96,7 @@ namespace fgl::engine::memory
|
||||
m_buffer_handles = handles;
|
||||
return handles;
|
||||
}
|
||||
#endif
|
||||
|
||||
vk::DeviceSize Buffer::alignment()
|
||||
{
|
||||
@@ -113,23 +116,23 @@ namespace fgl::engine::memory
|
||||
}
|
||||
|
||||
std::shared_ptr< BufferSuballocationHandle > Buffer::
|
||||
suballocate( vk::DeviceSize memory_size, std::uint32_t allignment )
|
||||
allocate( vk::DeviceSize memory_size, std::uint32_t t_alignment )
|
||||
{
|
||||
ZoneScoped;
|
||||
//Calculate alignment from alignment, ubo_alignment, and atom_size_alignment
|
||||
memory_size = align( memory_size, alignment() );
|
||||
|
||||
auto findBlock = [ this, memory_size, allignment ]()
|
||||
auto findBlock = [ this, memory_size, t_alignment ]()
|
||||
{
|
||||
//Find a free space.
|
||||
return std::find_if(
|
||||
m_free_blocks.begin(),
|
||||
m_free_blocks.end(),
|
||||
[ this, memory_size, allignment ]( const std::pair< vk::DeviceSize, vk::DeviceSize >& pair )
|
||||
[ this, memory_size, t_alignment ]( const std::pair< vk::DeviceSize, vk::DeviceSize >& pair )
|
||||
{
|
||||
const auto [ offset, size ] = pair;
|
||||
|
||||
const auto new_offset = align( offset, alignment(), allignment );
|
||||
const auto new_offset = align( offset, alignment(), t_alignment );
|
||||
const auto after_size { size - ( new_offset - offset ) };
|
||||
|
||||
// If the size of the block after alignment is greater than or equal to the size of the memory we want to allocate using it.
|
||||
@@ -156,14 +159,14 @@ namespace fgl::engine::memory
|
||||
{
|
||||
std::cout << "Offset: " << std::hex << offset << " Size: " << std::dec << size << "\n";
|
||||
|
||||
std::cout << "Aligned offset: " << std::hex << align( offset, alignment(), allignment )
|
||||
std::cout << "Aligned offset: " << std::hex << align( offset, alignment(), t_alignment )
|
||||
<< " Size: " << std::dec << size << "\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::cout << "====== Suballocations ======\n";
|
||||
|
||||
for ( auto [ offset, size ] : m_suballocations )
|
||||
for ( auto [ offset, size ] : m_allocations )
|
||||
{
|
||||
std::cout << "Offset: " << std::hex << offset << " Size: " << std::dec << size << "\n";
|
||||
}
|
||||
@@ -174,7 +177,7 @@ namespace fgl::engine::memory
|
||||
|
||||
std::uint64_t allocated_memory_counter { 0 };
|
||||
//Sum up all memory to check for leaks
|
||||
for ( auto [ offset, size ] : m_suballocations )
|
||||
for ( auto [ offset, size ] : m_allocations )
|
||||
{
|
||||
allocated_memory_counter += size;
|
||||
}
|
||||
@@ -207,7 +210,7 @@ namespace fgl::engine::memory
|
||||
auto [ offset, size ] = *itter;
|
||||
m_free_blocks.erase( itter );
|
||||
|
||||
const auto aligned_offset { align( offset, alignment(), allignment ) };
|
||||
const auto aligned_offset { align( offset, alignment(), t_alignment ) };
|
||||
|
||||
//Fix the offset and size if they aren't alligned
|
||||
if ( aligned_offset != offset )
|
||||
@@ -224,7 +227,7 @@ namespace fgl::engine::memory
|
||||
}
|
||||
|
||||
//Add the suballocation
|
||||
m_suballocations.insert_or_assign( offset, memory_size );
|
||||
m_allocations.insert_or_assign( offset, memory_size );
|
||||
|
||||
//If there is any memory left over, Then add it back into the free blocks
|
||||
if ( size - memory_size > 0 )
|
||||
@@ -238,7 +241,7 @@ namespace fgl::engine::memory
|
||||
sum += free_blocks.second;
|
||||
}
|
||||
|
||||
for ( const auto& allocated : this->m_suballocations )
|
||||
for ( const auto& allocated : this->m_allocations )
|
||||
{
|
||||
sum += allocated.second;
|
||||
}
|
||||
@@ -310,12 +313,12 @@ namespace fgl::engine::memory
|
||||
ZoneScoped;
|
||||
|
||||
//Find the suballocation
|
||||
auto itter = m_suballocations.find( info.m_offset );
|
||||
auto itter = m_allocations.find( info.m_offset );
|
||||
|
||||
if ( itter == m_suballocations.end() ) throw std::runtime_error( "Failed to find suballocation" );
|
||||
if ( itter == m_allocations.end() ) throw std::runtime_error( "Failed to find suballocation" );
|
||||
|
||||
//Remove the suballocation
|
||||
m_suballocations.erase( itter );
|
||||
m_allocations.erase( itter );
|
||||
|
||||
//Add the block back to the free blocks
|
||||
m_free_blocks.emplace_back( std::make_pair( info.m_offset, info.m_size ) );
|
||||
@@ -330,7 +333,7 @@ namespace fgl::engine::memory
|
||||
sum += free_blocks.second;
|
||||
}
|
||||
|
||||
for ( const auto& allocated : this->m_suballocations )
|
||||
for ( const auto& allocated : this->m_allocations )
|
||||
{
|
||||
sum += allocated.second;
|
||||
}
|
||||
@@ -351,12 +354,14 @@ namespace fgl::engine::memory
|
||||
m_memory_properties( memory_properties )
|
||||
{
|
||||
m_free_blocks.insert( m_free_blocks.begin(), { 0, memory_size } );
|
||||
#ifdef TRACK_BUFFERS
|
||||
m_buffer_handles.emplace_back( m_handle );
|
||||
#endif
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
assert( m_suballocations.size() == 0 && "Buffer destructed while allocations still present" );
|
||||
assert( m_allocations.size() == 0 && "Buffer destructed while allocations still present" );
|
||||
}
|
||||
|
||||
} // namespace fgl::engine::memory
|
||||
|
||||
@@ -32,7 +32,9 @@ namespace fgl::engine::memory
|
||||
//TODO: Dynamic/onDemand resizing of Buffer for suballocations
|
||||
//TODO: Defragmentation
|
||||
|
||||
class BufferHandle
|
||||
//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
|
||||
{
|
||||
vk::Buffer m_buffer { VK_NULL_HANDLE };
|
||||
VmaAllocation m_allocation {};
|
||||
@@ -46,8 +48,6 @@ namespace fgl::engine::memory
|
||||
void alloc( vk::DeviceSize memory_size );
|
||||
void dealloc();
|
||||
|
||||
public:
|
||||
|
||||
BufferHandle() = delete;
|
||||
BufferHandle( const BufferHandle& other ) = delete;
|
||||
BufferHandle& operator=( const BufferHandle& other ) = delete;
|
||||
@@ -70,8 +70,21 @@ namespace fgl::engine::memory
|
||||
|
||||
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();
|
||||
|
||||
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:
|
||||
@@ -91,8 +104,6 @@ namespace fgl::engine::memory
|
||||
Buffer( Buffer&& other ) = default;
|
||||
Buffer& operator=( Buffer&& other ) = default;
|
||||
|
||||
static std::vector< std::weak_ptr< BufferHandle > > getActiveBufferHandles();
|
||||
|
||||
inline vk::Buffer& getVkBuffer() noexcept { return m_handle->m_buffer; }
|
||||
|
||||
//! Returns the required alignment for this buffer.
|
||||
@@ -104,7 +115,7 @@ namespace fgl::engine::memory
|
||||
|
||||
//! @brief List of all active suballocations
|
||||
//! <offset, size>
|
||||
std::map< vk::DeviceSize, vk::DeviceSize > m_suballocations {};
|
||||
std::map< vk::DeviceSize, vk::DeviceSize > m_allocations {};
|
||||
|
||||
//! @brief list of any free blocks
|
||||
//! @note All blocks are amalgamated to the largest they can expand to.
|
||||
@@ -164,7 +175,7 @@ namespace fgl::engine::memory
|
||||
* @note Alignment for atom_size is 0 if buffer is not host visible
|
||||
*/
|
||||
std::shared_ptr< BufferSuballocationHandle >
|
||||
suballocate( vk::DeviceSize memory_size, std::uint32_t alignment = 1 );
|
||||
allocate( vk::DeviceSize memory_size, std::uint32_t alignment = 1 );
|
||||
|
||||
//! Frees a given suballocation. After calling this the handle is invalid and accessing it is UB
|
||||
void free( BufferSuballocationHandle& info );
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace fgl::engine::memory
|
||||
}
|
||||
|
||||
BufferSuballocation::BufferSuballocation( Buffer& buffer, const vk::DeviceSize size ) :
|
||||
BufferSuballocation( buffer.suballocate( size ) )
|
||||
BufferSuballocation( buffer.allocate( size ) )
|
||||
{}
|
||||
|
||||
} // namespace fgl::engine
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace fgl::engine
|
||||
HostSingleT& operator=( const HostSingleT& ) = delete;
|
||||
|
||||
HostSingleT( memory::Buffer& buffer ) :
|
||||
memory::BufferSuballocation( buffer.suballocate( sizeof( T ), alignof( T ) ) )
|
||||
memory::BufferSuballocation( buffer.allocate( sizeof( T ), alignof( T ) ) )
|
||||
{}
|
||||
|
||||
HostSingleT& operator=( T& t )
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace fgl::engine::memory
|
||||
{
|
||||
|
||||
[[nodiscard]] BufferVector::BufferVector( Buffer& buffer, std::uint32_t count, std::uint32_t stride ) :
|
||||
BufferSuballocation( buffer.suballocate( count * stride ) ),
|
||||
BufferSuballocation( buffer.allocate( count * stride ) ),
|
||||
m_count( count ),
|
||||
m_stride( stride )
|
||||
{}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace fgl::engine
|
||||
|
||||
/**
|
||||
* @brief Constructs a new DeviceVector from a vector using an allocation of the supplied buffer
|
||||
* @param buffer buffer to suballocate from
|
||||
* @param buffer buffer to allocate from
|
||||
* @param data
|
||||
*/
|
||||
DeviceVector( memory::Buffer& buffer, const std::vector< T >& data ) :
|
||||
|
||||
Reference in New Issue
Block a user