Implement basic buffer resizing
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
#include "engine/debug/timing/FlameGraph.hpp"
|
||||
#include "engine/flags.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
#include "safe_include.hpp"
|
||||
|
||||
namespace fgl::engine::gui
|
||||
@@ -35,8 +36,11 @@ namespace fgl::engine::gui
|
||||
auto& [ gpu_allocated, gpu_used, gpu_largest_free ] = info.m_gpu;
|
||||
auto& [ host_allocated, host_used, host_largest_free ] = info.m_host;
|
||||
|
||||
for ( const auto* buffer : memory::getActiveBuffers() )
|
||||
/*
|
||||
for ( const std::weak_ptr< memory::BufferHandle > buffer_weak : memory::getActiveBuffers() )
|
||||
{
|
||||
const auto buffer { buffer_weak.lock() };
|
||||
|
||||
// The buffer is still active.
|
||||
if ( buffer->m_memory_properties & vk::MemoryPropertyFlagBits::eDeviceLocal )
|
||||
{
|
||||
@@ -53,6 +57,7 @@ namespace fgl::engine::gui
|
||||
else
|
||||
throw std::runtime_error( "Unknown memory property flag choice. Could not determine host vs device" );
|
||||
}
|
||||
*/
|
||||
|
||||
return info;
|
||||
}
|
||||
@@ -88,8 +93,10 @@ namespace fgl::engine::gui
|
||||
|
||||
if ( ImGui::CollapsingHeader( "Buffers" ) )
|
||||
{
|
||||
for ( const auto* buffer : memory::getActiveBuffers() )
|
||||
/*
|
||||
for ( const std::weak_ptr< memory::BufferHandle > buffer_weak : memory::getActiveBuffers() )
|
||||
{
|
||||
const auto buffer { buffer_weak.lock() };
|
||||
ImGui::Text( "Name: %s", buffer->m_debug_name.c_str() );
|
||||
|
||||
const double used_percent { static_cast< float >( buffer->used() )
|
||||
@@ -104,6 +111,7 @@ namespace fgl::engine::gui
|
||||
ImGui::Text( "Largest block: %s", toString( buffer->largestBlock() ).c_str() );
|
||||
ImGui::Separator();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "engine/flags.hpp"
|
||||
#include "engine/math/Average.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
@@ -52,7 +53,7 @@ namespace fgl::engine
|
||||
EngineContext::EngineContext() :
|
||||
m_ubo_buffer_pool( 1_MiB, vk::BufferUsageFlagBits::eUniformBuffer, vk::MemoryPropertyFlagBits::eHostVisible ),
|
||||
m_draw_parameter_pool(
|
||||
128_MiB,
|
||||
4_MiB,
|
||||
vk::BufferUsageFlagBits::eIndirectBuffer | vk::BufferUsageFlagBits::eStorageBuffer,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ),
|
||||
m_gpu_draw_commands(
|
||||
@@ -68,7 +69,7 @@ namespace fgl::engine
|
||||
|
||||
// memory::TransferManager::createInstance( device, 128_MiB );
|
||||
|
||||
m_draw_parameter_pool.setDebugName( "Draw parameter pool" );
|
||||
m_draw_parameter_pool->setDebugName( "Draw parameter pool" );
|
||||
}
|
||||
|
||||
static Average< float, 60 * 15 > rolling_ms_average;
|
||||
@@ -159,9 +160,6 @@ namespace fgl::engine
|
||||
|
||||
TracyVkCollect( frame_info.tracy_ctx, **command_buffers.transfer_cb );
|
||||
|
||||
//TODO: Setup semaphores to make this pass not always required.
|
||||
m_transfer_manager.recordOwnershipTransferDst( command_buffers.transfer_cb );
|
||||
|
||||
for ( const auto& hook : m_early_render_hooks ) hook( frame_info );
|
||||
//TODO: Add some way of 'activating' cameras. We don't need to render cameras that aren't active.
|
||||
renderCameras( frame_info );
|
||||
@@ -175,9 +173,13 @@ namespace fgl::engine
|
||||
|
||||
m_renderer.endSwapchainRendererPass( command_buffers.imgui_cb );
|
||||
|
||||
m_transfer_manager.recordOwnershipTransferDst( command_buffers.transfer_cb );
|
||||
|
||||
m_renderer.endFrame( command_buffers );
|
||||
|
||||
//TODO: Setup semaphores to make this pass not always required.
|
||||
m_transfer_manager.dump();
|
||||
|
||||
m_device.getCmdBufferPool().advanceInFlight();
|
||||
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace fgl::engine
|
||||
|
||||
CameraManager m_camera_manager {};
|
||||
|
||||
memory::TransferManager m_transfer_manager { m_device, 128_MiB };
|
||||
memory::TransferManager m_transfer_manager { m_device, 32_MiB };
|
||||
|
||||
std::chrono::time_point< Clock > m_last_tick { Clock::now() };
|
||||
DeltaTime m_delta_time;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "material/Material.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
@@ -24,7 +25,7 @@ namespace fgl::engine
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ),
|
||||
m_material_data( m_material_data_pool, MAX_MATERIAL_COUNT )
|
||||
{
|
||||
m_material_data_pool.setDebugName( "Material data pool" );
|
||||
m_material_data_pool->setDebugName( "Material data pool" );
|
||||
}
|
||||
|
||||
MaterialManager::~MaterialManager()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "material/Material.hpp"
|
||||
#include "memory/buffers/vector/DeviceVector.hpp"
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace fgl::engine
|
||||
vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible ),
|
||||
m_vertex_buffer(
|
||||
256_MiB,
|
||||
2_MiB,
|
||||
vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eStorageBuffer
|
||||
| vk::BufferUsageFlagBits::eTransferDst,
|
||||
vk::MemoryPropertyFlagBits::eDeviceLocal ),
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace fgl::engine
|
||||
|
||||
namespace memory
|
||||
{
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
}
|
||||
|
||||
struct ModelBuilder;
|
||||
|
||||
@@ -8,27 +8,24 @@
|
||||
#include <vector>
|
||||
|
||||
#include "engine/primitives/Transform.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
struct ModelVertex;
|
||||
struct Primitive;
|
||||
|
||||
namespace memory
|
||||
{
|
||||
class Buffer;
|
||||
}
|
||||
|
||||
struct ModelBuilder
|
||||
{
|
||||
memory::Buffer& m_vertex_buffer;
|
||||
memory::Buffer& m_index_buffer;
|
||||
memory::Buffer m_vertex_buffer;
|
||||
memory::Buffer m_index_buffer;
|
||||
|
||||
std::vector< Primitive > m_primitives {};
|
||||
|
||||
ModelBuilder() = delete;
|
||||
|
||||
ModelBuilder( memory::Buffer& parent_vertex_buffer, memory::Buffer& parent_index_buffer ) :
|
||||
ModelBuilder(
|
||||
const memory::Buffer& parent_vertex_buffer, const memory::Buffer& parent_index_buffer ) :
|
||||
m_vertex_buffer( parent_vertex_buffer ),
|
||||
m_index_buffer( parent_index_buffer )
|
||||
{}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "assets/model/ModelVertex.hpp"
|
||||
#include "engine/assets/image/ImageView.hpp"
|
||||
#include "engine/assets/stores.hpp"
|
||||
#include "engine/camera/Camera.hpp"
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
@@ -23,7 +22,7 @@
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
SceneBuilder::SceneBuilder( memory::Buffer& vertex_buffer, memory::Buffer& index_buffer ) :
|
||||
SceneBuilder::SceneBuilder( const memory::Buffer& vertex_buffer, const memory::Buffer& index_buffer ) :
|
||||
m_vertex_buffer( vertex_buffer ),
|
||||
m_index_buffer( index_buffer )
|
||||
{}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace fgl::engine
|
||||
|
||||
namespace memory
|
||||
{
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
}
|
||||
|
||||
} // namespace fgl::engine
|
||||
@@ -50,8 +50,8 @@ namespace fgl::engine
|
||||
{
|
||||
//! Root path. Set by 'load' functions
|
||||
std::filesystem::path m_root {};
|
||||
memory::Buffer& m_vertex_buffer;
|
||||
memory::Buffer& m_index_buffer;
|
||||
memory::Buffer m_vertex_buffer;
|
||||
memory::Buffer m_index_buffer;
|
||||
|
||||
std::vector< GameObject > game_objects {};
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace fgl::engine
|
||||
|
||||
SceneBuilder() = delete;
|
||||
|
||||
SceneBuilder( memory::Buffer& vertex_buffer, memory::Buffer& index_buffer );
|
||||
SceneBuilder( const memory::Buffer& vertex_buffer, const memory::Buffer& index_buffer );
|
||||
|
||||
void loadScene( const std::filesystem::path& path );
|
||||
};
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include "engine/assets/image/ImageHandle.hpp"
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "engine/memory/buffers/exceptions.hpp"
|
||||
#include "engine/memory/buffers/vector/HostVector.hpp"
|
||||
#include "engine/utils.hpp"
|
||||
@@ -107,8 +106,8 @@ namespace fgl::engine::memory
|
||||
bool TransferData::performRawImageStage(
|
||||
vk::raii::CommandBuffer& buffer,
|
||||
Buffer& staging_buffer,
|
||||
std::uint32_t transfer_idx,
|
||||
std::uint32_t graphics_idx )
|
||||
const std::uint32_t transfer_idx,
|
||||
const std::uint32_t graphics_idx )
|
||||
{
|
||||
if ( !convertRawToBuffer( staging_buffer ) ) return false;
|
||||
return performImageStage( buffer, transfer_idx, graphics_idx );
|
||||
@@ -147,10 +146,10 @@ namespace fgl::engine::memory
|
||||
{
|
||||
// Prepare the staging buffer first.
|
||||
assert( std::holds_alternative< RawData >( m_source ) );
|
||||
assert( std::get< RawData >( m_source ).size() > 0 );
|
||||
assert( !std::get< RawData >( m_source ).empty() );
|
||||
|
||||
// Check if we are capable of allocating into the staging buffer
|
||||
if ( !staging_buffer.canAllocate( std::get< RawData >( m_source ).size(), 1 ) ) return false;
|
||||
if ( !staging_buffer->canAllocate( std::get< RawData >( m_source ).size(), 1 ) ) return false;
|
||||
|
||||
HostVector< std::byte > vector { staging_buffer, std::get< RawData >( m_source ) };
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
namespace raii
|
||||
@@ -27,7 +29,7 @@ namespace fgl::engine
|
||||
namespace memory
|
||||
{
|
||||
struct BufferSuballocationHandle;
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
} // namespace memory
|
||||
} // namespace fgl::engine
|
||||
|
||||
@@ -87,8 +89,8 @@ namespace fgl::engine::memory
|
||||
bool performRawImageStage(
|
||||
vk::raii::CommandBuffer& buffer,
|
||||
Buffer& staging_buffer,
|
||||
std::uint32_t graphics_idx,
|
||||
std::uint32_t transfer_idx );
|
||||
std::uint32_t transfer_idx,
|
||||
std::uint32_t graphics_idx );
|
||||
|
||||
bool performBufferStage( CopyRegionMap& copy_regions );
|
||||
|
||||
@@ -126,12 +128,12 @@ namespace fgl::engine::memory
|
||||
TransferData(
|
||||
const std::shared_ptr< BufferSuballocationHandle >& source,
|
||||
const std::shared_ptr< BufferSuballocationHandle >& target,
|
||||
const std::size_t offset );
|
||||
std::size_t offset );
|
||||
|
||||
TransferData(
|
||||
std::vector< std::byte >&& source,
|
||||
const std::shared_ptr< BufferSuballocationHandle >& target,
|
||||
const std::size_t offset );
|
||||
std::size_t offset );
|
||||
|
||||
//IMAGE_FROM_X
|
||||
TransferData(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "engine/assets/image/ImageHandle.hpp"
|
||||
#include "engine/assets/texture/Texture.hpp"
|
||||
#include "engine/math/literals/size.hpp"
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "engine/memory/buffers/BufferSuballocation.hpp"
|
||||
#include "engine/memory/buffers/vector/HostVector.hpp"
|
||||
|
||||
@@ -19,12 +19,12 @@ namespace fgl::engine::memory
|
||||
ZoneScoped;
|
||||
//Keep inserting new commands until we fill up the staging buffer
|
||||
|
||||
if ( m_queue.size() > 0 ) log::info( "[TransferManager]: Queue size: {}", m_queue.size() );
|
||||
if ( !m_queue.empty() ) log::info( "[TransferManager]: Queue size: {}", m_queue.size() );
|
||||
|
||||
std::size_t counter { 0 };
|
||||
constexpr std::size_t counter_max { 256 };
|
||||
|
||||
while ( m_queue.size() > 0 )
|
||||
while ( !m_queue.empty() )
|
||||
{
|
||||
++counter;
|
||||
if ( counter > counter_max ) break;
|
||||
@@ -34,7 +34,7 @@ namespace fgl::engine::memory
|
||||
|
||||
if ( data.stage(
|
||||
command_buffer,
|
||||
*m_staging_buffer,
|
||||
m_staging_buffer,
|
||||
m_copy_regions,
|
||||
m_transfer_queue_index,
|
||||
m_graphics_queue_index ) )
|
||||
@@ -44,7 +44,7 @@ namespace fgl::engine::memory
|
||||
else
|
||||
{
|
||||
// We were unable to stage for a reason
|
||||
log::info( "Unable to stage object. Breaking out of loop" );
|
||||
log::debug( "Unable to stage object. Breaking out of loop, Objects will be staged next pass" );
|
||||
m_queue.push( data );
|
||||
break;
|
||||
}
|
||||
@@ -92,10 +92,7 @@ namespace fgl::engine::memory
|
||||
|
||||
void TransferManager::resizeBuffer( const std::uint64_t size )
|
||||
{
|
||||
m_staging_buffer = std::make_unique< Buffer >(
|
||||
size,
|
||||
vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent );
|
||||
m_staging_buffer->resize( size );
|
||||
}
|
||||
|
||||
void TransferManager::submitBuffer( vk::raii::CommandBuffer& command_buffer )
|
||||
@@ -258,6 +255,7 @@ namespace fgl::engine::memory
|
||||
|
||||
m_processing.clear();
|
||||
m_copy_regions.clear();
|
||||
m_allow_transfers = true;
|
||||
}
|
||||
|
||||
TransferManager& TransferManager::getInstance()
|
||||
@@ -273,7 +271,7 @@ namespace fgl::engine::memory
|
||||
m_queue.emplace( std::move( transfer_data ) );
|
||||
}
|
||||
|
||||
void TransferManager::copyToImage( std::vector< std::byte >&& data, Image& image )
|
||||
void TransferManager::copyToImage( std::vector< std::byte >&& data, const Image& image )
|
||||
{
|
||||
assert( data.size() > 0 );
|
||||
TransferData transfer_data { std::forward< std::vector< std::byte > >( data ), image.m_handle };
|
||||
@@ -283,12 +281,11 @@ namespace fgl::engine::memory
|
||||
m_queue.emplace( std::move( transfer_data ) );
|
||||
}
|
||||
|
||||
TransferManager::TransferManager( Device& device, std::uint64_t buffer_size ) :
|
||||
TransferManager::TransferManager( Device& device, const vk::DeviceSize buffer_size ) :
|
||||
m_staging_buffer(
|
||||
std::make_unique< Buffer >(
|
||||
buffer_size,
|
||||
vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent ) ),
|
||||
buffer_size,
|
||||
vk::BufferUsageFlagBits::eTransferSrc,
|
||||
vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent ),
|
||||
m_transfer_queue_index( device.phyDevice()
|
||||
.queueInfo()
|
||||
.getIndex( vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics ) ),
|
||||
@@ -308,6 +305,8 @@ namespace fgl::engine::memory
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
m_allow_transfers = false;
|
||||
|
||||
auto& transfer_buffer { m_transfer_buffers[ 0 ] };
|
||||
transfer_buffer.reset();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace fgl::engine::memory
|
||||
//TODO: Ring Buffer
|
||||
|
||||
//! Buffer used for any raw -> buffer transfers
|
||||
std::unique_ptr< Buffer > m_staging_buffer {};
|
||||
Buffer m_staging_buffer;
|
||||
|
||||
//! Queue of data needing to be transfered and submitted.
|
||||
std::queue< TransferData > m_queue {};
|
||||
@@ -59,6 +59,9 @@ namespace fgl::engine::memory
|
||||
|
||||
vk::raii::Fence m_completion_fence;
|
||||
|
||||
//! True if transfers would be performed before the start of the next frame
|
||||
bool m_allow_transfers { true };
|
||||
|
||||
void recordCommands( vk::raii::CommandBuffer& command_buffer );
|
||||
|
||||
void submitBuffer( vk::raii::CommandBuffer& command_buffer );
|
||||
@@ -77,7 +80,7 @@ namespace fgl::engine::memory
|
||||
|
||||
public:
|
||||
|
||||
TransferManager( Device& device, std::uint64_t buffer_size );
|
||||
TransferManager( Device& device, vk::DeviceSize buffer_size );
|
||||
|
||||
FGL_DELETE_ALL_RO5( TransferManager );
|
||||
|
||||
@@ -97,6 +100,22 @@ namespace fgl::engine::memory
|
||||
//! Resizes the staging buffer.
|
||||
void resizeBuffer( std::uint64_t size );
|
||||
|
||||
void copySuballocationRegion(
|
||||
const std::shared_ptr< BufferSuballocationHandle >& src,
|
||||
const std::shared_ptr< BufferSuballocationHandle >& dst,
|
||||
const std::size_t offset = 0 )
|
||||
{
|
||||
FGL_ASSERT( src->m_size == dst->m_size, "Source and destination suballocations must be the same size" );
|
||||
|
||||
TransferData transfer_data {
|
||||
src,
|
||||
dst,
|
||||
offset,
|
||||
};
|
||||
|
||||
m_queue.emplace( std::move( transfer_data ) );
|
||||
}
|
||||
|
||||
//! Queues a buffer to be transfered
|
||||
template < typename DeviceVectorT >
|
||||
requires is_device_vector< DeviceVectorT >
|
||||
@@ -140,7 +159,7 @@ namespace fgl::engine::memory
|
||||
|
||||
void copyToVector( BufferVector& source, BufferVector& target, std::size_t target_offset );
|
||||
|
||||
void copyToImage( std::vector< std::byte >&& data, Image& image );
|
||||
void copyToImage( std::vector< std::byte >&& data, const Image& image );
|
||||
|
||||
//! Forces the queue to be submitted now before the buffer is filled.
|
||||
void submitNow();
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace fgl::engine
|
||||
void updateInfo( FrameIndex frame_index );
|
||||
descriptors::DescriptorSet& getDescriptor( FrameIndex index );
|
||||
|
||||
void setFOV( const float fov_y );
|
||||
void setFOV( float fov_y );
|
||||
|
||||
//! Performs the render pass for this camera
|
||||
void pass( FrameInfo& frame_info );
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Camera.hpp"
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
|
||||
@@ -35,7 +35,8 @@ namespace fgl::engine::debug
|
||||
|
||||
void deregisterTrack( const std::size_t UID )
|
||||
{
|
||||
assert( track_info.erase( UID ) > 0 && "Unable to find UID" );
|
||||
track_info.erase( UID );
|
||||
// assert( track_info.erase( UID ) > 0 && "Unable to find UID" );
|
||||
}
|
||||
|
||||
std::vector< TrackInfo > getTracks( const std::string_view group, const std::string_view name )
|
||||
|
||||
@@ -28,10 +28,12 @@ namespace fgl::engine::debug
|
||||
std::vector< TrackInfo > getTracks( std::string_view group, std::string_view name );
|
||||
std::vector< TrackInfo > getAllTracks();
|
||||
|
||||
constexpr TrackUID INVALID_TRACK_ID { std::numeric_limits< TrackUID >::max() };
|
||||
|
||||
template < TString Group, TString Name >
|
||||
class Track
|
||||
{
|
||||
TrackUID UID;
|
||||
TrackUID UID { INVALID_TRACK_ID };
|
||||
|
||||
public:
|
||||
|
||||
@@ -39,6 +41,11 @@ namespace fgl::engine::debug
|
||||
UID( registerTrack( Group, Name, size, trace ) )
|
||||
{}
|
||||
|
||||
Track( Track&& other ) = default;
|
||||
Track( const Track& other ) = default;
|
||||
Track& operator=( Track&& other ) = default;
|
||||
Track& operator=( const Track& other ) = default;
|
||||
|
||||
~Track() { deregisterTrack( UID ); }
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace fgl::engine::descriptors
|
||||
{
|
||||
|
||||
11
src/engine/memory/DefferedCleanup.hpp
Normal file
11
src/engine/memory/DefferedCleanup.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by kj16609 on 4/9/25.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
|
||||
void deferredDelete( auto&& item ) {}
|
||||
|
||||
}
|
||||
@@ -2,27 +2,39 @@
|
||||
// Created by kj16609 on 12/30/23.
|
||||
//
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "BufferHandle.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
#include "BufferSuballocationHandle.hpp"
|
||||
#include "align.hpp"
|
||||
#include "assets/transfer/TransferManager.hpp"
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "engine/memory/buffers/exceptions.hpp"
|
||||
#include "engine/rendering/devices/Device.hpp"
|
||||
#include "memory/DefferedCleanup.hpp"
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
|
||||
inline static std::vector< Buffer* > active_buffers {};
|
||||
|
||||
std::vector< Buffer* > getActiveBuffers()
|
||||
void BufferHandle::swap( BufferHandle& other ) noexcept
|
||||
{
|
||||
return active_buffers;
|
||||
std::swap( m_buffer, other.m_buffer );
|
||||
std::swap( m_allocation, other.m_allocation );
|
||||
std::swap( m_alloc_info, other.m_alloc_info );
|
||||
std::swap( m_memory_size, other.m_memory_size );
|
||||
std::swap( m_usage, other.m_usage );
|
||||
std::swap( m_memory_properties, other.m_memory_properties );
|
||||
std::swap( m_track, other.m_track );
|
||||
std::swap( m_debug_name, other.m_debug_name );
|
||||
std::swap( m_active_suballocations, other.m_active_suballocations );
|
||||
std::swap( m_allocation_traces, other.m_allocation_traces );
|
||||
std::swap( m_free_blocks, other.m_free_blocks );
|
||||
}
|
||||
|
||||
Buffer::Buffer(
|
||||
BufferHandle::BufferHandle(
|
||||
vk::DeviceSize memory_size,
|
||||
const vk::BufferUsageFlags usage,
|
||||
const vk::MemoryPropertyFlags memory_properties ) :
|
||||
@@ -30,19 +42,27 @@ namespace fgl::engine::memory
|
||||
m_usage( usage ),
|
||||
m_memory_properties( memory_properties )
|
||||
{
|
||||
alloc( memory_size );
|
||||
active_buffers.emplace_back( this );
|
||||
auto [ buffer, vma_alloc_info, vma_allocation ] = allocBuffer( memory_size, m_usage, m_memory_properties );
|
||||
|
||||
m_buffer = buffer;
|
||||
m_alloc_info = vma_alloc_info;
|
||||
m_allocation = vma_allocation;
|
||||
|
||||
m_free_blocks.emplace_back( 0, memory_size );
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
BufferHandle::~BufferHandle()
|
||||
{
|
||||
if ( !m_allocations.empty() )
|
||||
if ( !m_active_suballocations.empty() )
|
||||
{
|
||||
log::critical( "Buffer allocations not empty. {} allocations left", m_allocations.size() );
|
||||
log::critical( "Buffer allocations not empty. {} allocations left", m_active_suballocations.size() );
|
||||
|
||||
for ( const auto& [ offset, size ] : m_allocations )
|
||||
for ( const auto& suballocation : m_active_suballocations )
|
||||
{
|
||||
if ( suballocation.expired() ) continue;
|
||||
auto suballoc_ptr { suballocation.lock() };
|
||||
const auto offset { suballoc_ptr->m_offset };
|
||||
const auto size { suballoc_ptr->m_size };
|
||||
log::info( "Stacktrace: Offset at {} with a size of {}", offset, size );
|
||||
|
||||
const auto itter = this->m_allocation_traces.find( offset );
|
||||
@@ -56,71 +76,78 @@ namespace fgl::engine::memory
|
||||
|
||||
log::critical( "Buffer allocations were not empty!" );
|
||||
// Call will always terminate
|
||||
// throw std::runtime_error( "Buffer allocations not empty" );
|
||||
throw std::runtime_error( "Buffer allocations not empty" );
|
||||
}
|
||||
|
||||
dealloc();
|
||||
|
||||
if ( const auto itter = std::ranges::find( active_buffers, this ); itter != active_buffers.end() )
|
||||
active_buffers.erase( itter );
|
||||
deallocBuffer( m_buffer, m_allocation );
|
||||
}
|
||||
|
||||
void* Buffer::map( const BufferSuballocationHandle& handle ) const
|
||||
void* BufferHandle::map( const BufferSuballocationHandle& handle ) const
|
||||
{
|
||||
if ( m_alloc_info.pMappedData == nullptr ) return nullptr;
|
||||
|
||||
return static_cast< std::byte* >( m_alloc_info.pMappedData ) + handle.m_offset;
|
||||
}
|
||||
|
||||
void Buffer::dealloc() const
|
||||
void BufferHandle::deallocBuffer( vk::Buffer& buffer, VmaAllocation& allocation )
|
||||
{
|
||||
vmaDestroyBuffer( Device::getInstance().allocator(), m_buffer, m_allocation );
|
||||
vmaDestroyBuffer( Device::getInstance().allocator(), buffer, allocation );
|
||||
}
|
||||
|
||||
void Buffer::alloc( const vk::DeviceSize memory_size )
|
||||
std::tuple< vk::Buffer, VmaAllocationInfo, VmaAllocation > BufferHandle::allocBuffer(
|
||||
const vk::DeviceSize memory_size, vk::BufferUsageFlags usage, const vk::MemoryPropertyFlags property_flags )
|
||||
{
|
||||
assert( !m_debug_name.empty() );
|
||||
// Used for resizing.
|
||||
//TODO: Make this only available if resize is desired. Otherwise do not have it.
|
||||
usage |= vk::BufferUsageFlagBits::eTransferDst;
|
||||
usage |= vk::BufferUsageFlagBits::eTransferSrc;
|
||||
|
||||
assert( memory_size > 0 );
|
||||
m_memory_size = memory_size;
|
||||
vk::BufferCreateInfo buffer_info {};
|
||||
buffer_info.pNext = VK_NULL_HANDLE;
|
||||
buffer_info.flags = {};
|
||||
buffer_info.size = m_memory_size;
|
||||
buffer_info.usage = m_usage;
|
||||
buffer_info.size = memory_size;
|
||||
buffer_info.usage = usage;
|
||||
buffer_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
buffer_info.queueFamilyIndexCount = 0;
|
||||
buffer_info.pQueueFamilyIndices = VK_NULL_HANDLE;
|
||||
|
||||
VmaAllocationCreateInfo alloc_info {};
|
||||
VmaAllocationCreateInfo create_info {};
|
||||
|
||||
alloc_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
create_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
|
||||
if ( m_memory_properties & vk::MemoryPropertyFlagBits::eHostVisible )
|
||||
alloc_info.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
if ( property_flags & vk::MemoryPropertyFlagBits::eHostVisible )
|
||||
create_info.flags |= VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
|
||||
if ( m_usage & vk::BufferUsageFlagBits::eTransferSrc )
|
||||
if ( usage & vk::BufferUsageFlagBits::eTransferSrc )
|
||||
{
|
||||
//Remove VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM BIT if we are transfer src
|
||||
alloc_info.flags &= ~VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
create_info.flags &= ~VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||
|
||||
alloc_info.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
create_info.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
}
|
||||
|
||||
VmaAllocationInfo alloc_info {};
|
||||
VmaAllocation allocation {};
|
||||
|
||||
const VkBufferCreateInfo& vk_buffer_info = buffer_info;
|
||||
VkBuffer buffer { VK_NULL_HANDLE };
|
||||
if ( vmaCreateBuffer(
|
||||
Device::getInstance().allocator(), &vk_buffer_info, &alloc_info, &buffer, &m_allocation, nullptr )
|
||||
Device::getInstance().allocator(), &vk_buffer_info, &create_info, &buffer, &allocation, nullptr )
|
||||
!= VK_SUCCESS )
|
||||
{
|
||||
throw BufferException( "Unable to allocate memory in VMA" );
|
||||
}
|
||||
|
||||
m_buffer = buffer;
|
||||
vmaGetAllocationInfo( Device::getInstance().allocator(), allocation, &alloc_info );
|
||||
|
||||
vmaGetAllocationInfo( Device::getInstance().allocator(), m_allocation, &m_alloc_info );
|
||||
return std::make_tuple<
|
||||
vk::Buffer,
|
||||
VmaAllocationInfo,
|
||||
VmaAllocation >( std::move( buffer ), std::move( alloc_info ), std::move( allocation ) );
|
||||
}
|
||||
|
||||
vk::DeviceSize Buffer::alignment() const
|
||||
vk::DeviceSize BufferHandle::alignment() const
|
||||
{
|
||||
vk::DeviceSize size { 1 };
|
||||
|
||||
@@ -142,7 +169,7 @@ namespace fgl::engine::memory
|
||||
return size;
|
||||
}
|
||||
|
||||
decltype( Buffer::m_free_blocks )::iterator Buffer::
|
||||
decltype( BufferHandle::m_free_blocks )::iterator BufferHandle::
|
||||
findAvailableBlock( vk::DeviceSize memory_size, std::uint32_t t_alignment )
|
||||
{
|
||||
//Find a free space.
|
||||
@@ -160,7 +187,63 @@ namespace fgl::engine::memory
|
||||
} );
|
||||
}
|
||||
|
||||
std::shared_ptr< BufferSuballocationHandle > Buffer::
|
||||
void BufferHandle::resize( const vk::DeviceSize new_size )
|
||||
{
|
||||
log::warn( "Resizing buffer from {} to {}", size(), new_size );
|
||||
|
||||
std::shared_ptr< BufferHandle > new_handle { new BufferHandle( new_size, m_usage, m_memory_properties ) };
|
||||
|
||||
//Now we need to re-create all the current live allocations and transfer/replace them using the new buffer
|
||||
std::vector<
|
||||
std::pair< std::shared_ptr< BufferSuballocationHandle >, std::shared_ptr< BufferSuballocationHandle > > >
|
||||
allocations {};
|
||||
|
||||
allocations.reserve( m_active_suballocations.size() );
|
||||
|
||||
for ( auto& suballocation_weak : m_active_suballocations )
|
||||
{
|
||||
if ( suballocation_weak.expired() ) continue;
|
||||
try
|
||||
{
|
||||
auto suballocation { suballocation_weak.lock() };
|
||||
|
||||
auto new_suballocation { new_handle->allocate( suballocation->m_size, suballocation->m_alignment ) };
|
||||
allocations.emplace_back( std::make_pair( suballocation, new_suballocation ) );
|
||||
}
|
||||
catch ( std::bad_weak_ptr& e )
|
||||
{
|
||||
// noop
|
||||
void();
|
||||
}
|
||||
}
|
||||
|
||||
std::swap( m_buffer, new_handle->m_buffer );
|
||||
std::swap( m_alloc_info, new_handle->m_alloc_info );
|
||||
std::swap( m_allocation, new_handle->m_allocation );
|
||||
std::swap( m_free_blocks, new_handle->m_free_blocks );
|
||||
std::swap( m_active_suballocations, new_handle->m_active_suballocations );
|
||||
std::swap( m_allocation_traces, new_handle->m_allocation_traces );
|
||||
|
||||
// This transforms any memory::Buffer to be the `new_handle` we allocated above.
|
||||
const auto old_handle { new_handle };
|
||||
FGL_ASSERT( old_handle.get() != this, "Old handle should not be the current buffer anymore!" );
|
||||
new_handle = this->shared_from_this();
|
||||
|
||||
for ( auto& [ old_allocation, new_allocation ] : allocations )
|
||||
{
|
||||
old_allocation->m_parent_buffer = old_handle;
|
||||
new_allocation->m_parent_buffer = new_handle;
|
||||
}
|
||||
|
||||
//Now we need to transfer the data from the old buffer to the new buffer
|
||||
for ( const auto& allocation : allocations )
|
||||
{
|
||||
const auto& [ old_suballocation, new_suballocation ] = allocation;
|
||||
TransferManager::getInstance().copySuballocationRegion( old_suballocation, new_suballocation );
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr< BufferSuballocationHandle > BufferHandle::
|
||||
allocate( vk::DeviceSize desired_memory_size, const std::uint32_t t_alignment )
|
||||
{
|
||||
ZoneScoped;
|
||||
@@ -173,8 +256,14 @@ namespace fgl::engine::memory
|
||||
|
||||
if ( !canAllocate( desired_memory_size, t_alignment ) )
|
||||
{
|
||||
//TODO: Write more detailed error message
|
||||
throw BufferOOM();
|
||||
// Resize to x1.5 the size, or the size plus the desired size x1.5, Whichever is bigger
|
||||
const auto optimal_size { std::
|
||||
max( static_cast< vk::DeviceSize >( this->size() * 2 ),
|
||||
this->size()
|
||||
+ static_cast< vk::DeviceSize >( desired_memory_size * 2 ) ) };
|
||||
this->resize( optimal_size );
|
||||
|
||||
FGL_ASSERT( optimal_size == this->size(), "Optimal size not met!" );
|
||||
}
|
||||
|
||||
auto itter { findAvailableBlock( desired_memory_size, t_alignment ) };
|
||||
@@ -209,9 +298,8 @@ namespace fgl::engine::memory
|
||||
selected_block_size -= leftover_start_size;
|
||||
}
|
||||
|
||||
//Add the suballocation
|
||||
m_allocations.insert_or_assign( selected_block_offset, desired_memory_size );
|
||||
|
||||
// Add the suballocation
|
||||
// m_allocations.insert_or_assign( selected_block_offset, desired_memory_size );
|
||||
m_allocation_traces.insert_or_assign( selected_block_offset, std::stacktrace::current() );
|
||||
|
||||
assert( selected_block_size >= desired_memory_size );
|
||||
@@ -226,26 +314,18 @@ namespace fgl::engine::memory
|
||||
.emplace_back( selected_block_offset + desired_memory_size, selected_block_size - desired_memory_size );
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
//Check that we haven't lost any memory
|
||||
std::size_t sum { 0 };
|
||||
for ( const auto& [ _, free_size ] : this->m_free_blocks )
|
||||
{
|
||||
sum += free_size;
|
||||
}
|
||||
std::ranges::
|
||||
remove_if( m_active_suballocations, []( auto& suballocation ) -> bool { return suballocation.expired(); } );
|
||||
|
||||
for ( const auto& [ _, allocated_size ] : this->m_allocations )
|
||||
{
|
||||
sum += allocated_size;
|
||||
}
|
||||
auto suballocation_handle { std::make_shared< BufferSuballocationHandle >(
|
||||
Buffer( this->shared_from_this() ), selected_block_offset, desired_memory_size, t_alignment ) };
|
||||
|
||||
assert( sum == this->size() );
|
||||
#endif
|
||||
m_active_suballocations.push_back( suballocation_handle );
|
||||
|
||||
return std::make_shared< BufferSuballocationHandle >( *this, selected_block_offset, desired_memory_size );
|
||||
return suballocation_handle;
|
||||
}
|
||||
|
||||
bool Buffer::canAllocate( const vk::DeviceSize memory_size, const std::uint32_t alignment )
|
||||
bool BufferHandle::canAllocate( const vk::DeviceSize memory_size, const std::uint32_t alignment )
|
||||
{
|
||||
// TODO: This check can be optimized by itterating through and virtually combining blocks that would be combined.
|
||||
// If the combined block is large enough then we should consider it being capable of allocation.
|
||||
@@ -256,11 +336,11 @@ namespace fgl::engine::memory
|
||||
mergeFreeBlocks();
|
||||
return findAvailableBlock( memory_size, alignment ) != m_free_blocks.end();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Buffer::mergeFreeBlocks()
|
||||
void BufferHandle::mergeFreeBlocks()
|
||||
{
|
||||
ZoneScoped;
|
||||
//Can't combine blocks if there is only 1
|
||||
@@ -304,7 +384,7 @@ namespace fgl::engine::memory
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer::setDebugName( const std::string& str )
|
||||
void BufferHandle::setDebugName( const std::string& str )
|
||||
{
|
||||
vk::DebugUtilsObjectNameInfoEXT info {};
|
||||
info.objectType = vk::ObjectType::eBuffer;
|
||||
@@ -316,18 +396,10 @@ namespace fgl::engine::memory
|
||||
Device::getInstance().setDebugUtilsObjectName( info );
|
||||
}
|
||||
|
||||
void Buffer::free( BufferSuballocationHandle& info )
|
||||
void BufferHandle::free( BufferSuballocationHandle& info )
|
||||
{
|
||||
ZoneScoped;
|
||||
|
||||
//Find the suballocation
|
||||
auto itter = m_allocations.find( info.m_offset );
|
||||
|
||||
if ( itter == m_allocations.end() ) throw std::runtime_error( "Failed to find suballocation" );
|
||||
|
||||
//Remove the suballocation
|
||||
m_allocations.erase( itter );
|
||||
|
||||
if ( info.m_offset >= this->size() ) throw std::runtime_error( "Offset was outside of bounds of buffer" );
|
||||
if ( info.m_offset + info.m_size > this->size() )
|
||||
throw std::runtime_error(
|
||||
@@ -351,9 +423,10 @@ namespace fgl::engine::memory
|
||||
sum += free_blocks.second;
|
||||
}
|
||||
|
||||
for ( const auto& allocated : this->m_allocations )
|
||||
for ( auto& suballocation : m_active_suballocations )
|
||||
{
|
||||
sum += allocated.second;
|
||||
if ( suballocation.expired() ) continue;
|
||||
sum += suballocation.lock()->m_size;
|
||||
}
|
||||
|
||||
if ( sum != this->size() )
|
||||
@@ -362,21 +435,19 @@ namespace fgl::engine::memory
|
||||
#endif
|
||||
}
|
||||
|
||||
vk::DeviceSize Buffer::used() const
|
||||
vk::DeviceSize BufferHandle::used() const
|
||||
{
|
||||
vk::DeviceSize total_size { 0 };
|
||||
|
||||
if ( m_allocations.size() == 0 ) return total_size;
|
||||
|
||||
for ( const auto& [ offset, size ] : m_allocations )
|
||||
for ( auto& suballocation : m_active_suballocations )
|
||||
{
|
||||
total_size += size;
|
||||
total_size += suballocation.lock()->m_size;
|
||||
}
|
||||
|
||||
return total_size;
|
||||
}
|
||||
|
||||
vk::DeviceSize Buffer::largestBlock() const
|
||||
vk::DeviceSize BufferHandle::largestBlock() const
|
||||
{
|
||||
vk::DeviceSize largest { 0 };
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include <memory>
|
||||
#include <stacktrace>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "FGL_DEFINES.hpp"
|
||||
#include "engine/debug/Track.hpp"
|
||||
#include "vma/vma_impl.hpp"
|
||||
|
||||
@@ -39,7 +41,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)
|
||||
class Buffer
|
||||
class BufferHandle : public std::enable_shared_from_this< BufferHandle >
|
||||
{
|
||||
vk::Buffer m_buffer { VK_NULL_HANDLE };
|
||||
VmaAllocation m_allocation {};
|
||||
@@ -52,26 +54,42 @@ namespace fgl::engine::memory
|
||||
vk::BufferUsageFlags m_usage;
|
||||
vk::MemoryPropertyFlags m_memory_properties;
|
||||
|
||||
std::vector< std::weak_ptr< BufferSuballocationHandle > > m_active_suballocations {};
|
||||
std::unordered_map< vk::DeviceSize, std::stacktrace > m_allocation_traces {};
|
||||
|
||||
//! @brief List of all active suballocations
|
||||
//! <offset, size>
|
||||
using AllocationSize = vk::DeviceSize;
|
||||
|
||||
//! @brief list of any free blocks
|
||||
//! @note All blocks are amalgamated to the largest they can expand to.
|
||||
//! <offset, size>
|
||||
std::vector< std::pair< vk::DeviceSize, vk::DeviceSize > > m_free_blocks {};
|
||||
|
||||
public:
|
||||
|
||||
std::string m_debug_name { "Debug name" };
|
||||
|
||||
private:
|
||||
|
||||
void alloc( vk::DeviceSize memory_size );
|
||||
void dealloc() const;
|
||||
static std::tuple< vk::Buffer, VmaAllocationInfo, VmaAllocation > allocBuffer(
|
||||
vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags property_flags );
|
||||
static void deallocBuffer( vk::Buffer&, VmaAllocation& );
|
||||
|
||||
Buffer() = delete;
|
||||
Buffer( const Buffer& other ) = delete;
|
||||
Buffer& operator=( const Buffer& other ) = delete;
|
||||
Buffer( Buffer&& other ) = delete;
|
||||
Buffer& operator=( Buffer&& other ) = delete;
|
||||
BufferHandle() = delete;
|
||||
BufferHandle( const BufferHandle& other ) = delete;
|
||||
BufferHandle& operator=( const BufferHandle& other ) = delete;
|
||||
BufferHandle( BufferHandle&& other ) = delete;
|
||||
BufferHandle& operator=( BufferHandle&& other ) = delete;
|
||||
|
||||
void swap( BufferHandle& other ) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties );
|
||||
BufferHandle(
|
||||
vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties );
|
||||
|
||||
~Buffer();
|
||||
~BufferHandle();
|
||||
|
||||
auto address() const { return m_alloc_info.deviceMemory; }
|
||||
|
||||
@@ -81,27 +99,6 @@ namespace fgl::engine::memory
|
||||
|
||||
vk::DeviceSize used() const;
|
||||
|
||||
private:
|
||||
|
||||
void* map( const BufferSuballocationHandle& handle ) const;
|
||||
|
||||
//! Returns the required alignment for this buffer.
|
||||
vk::DeviceSize alignment() const;
|
||||
|
||||
//! @brief List of all active suballocations
|
||||
//! <offset, size>
|
||||
using AllocationSize = vk::DeviceSize;
|
||||
|
||||
std::map< vk::DeviceSize, AllocationSize > m_allocations {};
|
||||
std::unordered_map< vk::DeviceSize, std::stacktrace > m_allocation_traces {};
|
||||
|
||||
//! @brief list of any free blocks
|
||||
//! @note All blocks are amalgamated to the largest they can expand to.
|
||||
//! <offset, size>
|
||||
std::vector< std::pair< vk::DeviceSize, vk::DeviceSize > > m_free_blocks {};
|
||||
|
||||
decltype( m_free_blocks )::iterator findAvailableBlock( vk::DeviceSize memory_size, std::uint32_t t_alignment );
|
||||
|
||||
public:
|
||||
|
||||
//! Returns the vulkan buffer handle for this buffer
|
||||
@@ -120,12 +117,12 @@ namespace fgl::engine::memory
|
||||
|
||||
friend gui::AllocationList gui::getTotalAllocated();
|
||||
|
||||
public:
|
||||
|
||||
bool isMappable() const { return m_alloc_info.pMappedData != nullptr; }
|
||||
|
||||
void resize( vk::DeviceSize new_size );
|
||||
//! 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)
|
||||
|
||||
/**
|
||||
* @param desired_memory_size Size of each N
|
||||
* @param alignment The alignment to use.
|
||||
@@ -150,7 +147,27 @@ namespace fgl::engine::memory
|
||||
void mergeFreeBlocks();
|
||||
|
||||
void setDebugName( const std::string& str );
|
||||
|
||||
private:
|
||||
|
||||
void* map( const BufferSuballocationHandle& handle ) const;
|
||||
|
||||
//! Returns the required alignment for this buffer.
|
||||
vk::DeviceSize alignment() const;
|
||||
|
||||
decltype( m_free_blocks )::iterator findAvailableBlock( vk::DeviceSize memory_size, std::uint32_t t_alignment );
|
||||
};
|
||||
|
||||
std::vector< Buffer* > getActiveBuffers();
|
||||
struct Buffer final : public std::shared_ptr< BufferHandle >
|
||||
{
|
||||
Buffer( vk::DeviceSize memory_size, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags memory_properties ) :
|
||||
std::shared_ptr< BufferHandle >( std::make_shared< BufferHandle >( memory_size, usage, memory_properties ) )
|
||||
{}
|
||||
|
||||
Buffer( const std::shared_ptr< BufferHandle >& buffer ) : std::shared_ptr< BufferHandle >( buffer ) {}
|
||||
|
||||
~Buffer() = default;
|
||||
};
|
||||
|
||||
std::vector< std::weak_ptr< Buffer > > getActiveBuffers();
|
||||
} // namespace fgl::engine::memory
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "BufferSuballocation.hpp"
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "BufferSuballocationHandle.hpp"
|
||||
#include "SuballocationView.hpp"
|
||||
#include "align.hpp"
|
||||
@@ -62,7 +61,7 @@ namespace fgl::engine::memory
|
||||
assert( end <= this->m_byte_size );
|
||||
|
||||
vk::MappedMemoryRange range {};
|
||||
range.memory = m_handle->m_buffer.getMemory();
|
||||
range.memory = m_handle->m_parent_buffer->getMemory();
|
||||
range.offset = m_offset + beg;
|
||||
|
||||
const vk::DeviceSize min_atom_size { Device::getInstance().m_properties.limits.nonCoherentAtomSize };
|
||||
@@ -85,14 +84,14 @@ namespace fgl::engine::memory
|
||||
{
|
||||
assert( m_handle != nullptr );
|
||||
|
||||
return m_handle->m_buffer;
|
||||
return m_handle->m_parent_buffer;
|
||||
}
|
||||
|
||||
vk::Buffer BufferSuballocation::getVkBuffer() const
|
||||
{
|
||||
assert( m_handle != nullptr );
|
||||
|
||||
return m_handle->m_buffer.getVkBuffer();
|
||||
return m_handle->m_parent_buffer->getVkBuffer();
|
||||
}
|
||||
|
||||
vk::DescriptorBufferInfo BufferSuballocation::descriptorInfo( const std::size_t byte_offset ) const
|
||||
@@ -102,7 +101,7 @@ namespace fgl::engine::memory
|
||||
|
||||
FGL_ASSERT( byte_offset < m_byte_size, "Byte offset was greater then byte size!" );
|
||||
FGL_ASSERT(
|
||||
m_offset + byte_offset < this->getBuffer().size(),
|
||||
m_offset + byte_offset < this->getBuffer()->size(),
|
||||
"Byte offset + buffer offset was greater then parent buffer size" );
|
||||
|
||||
return { getVkBuffer(), m_offset + byte_offset, m_byte_size };
|
||||
@@ -118,12 +117,12 @@ namespace fgl::engine::memory
|
||||
return { m_handle, offset, size };
|
||||
}
|
||||
|
||||
BufferSuballocation::BufferSuballocation( Buffer& buffer, const vk::DeviceSize size ) :
|
||||
BufferSuballocation( buffer.allocate( size ) )
|
||||
BufferSuballocation::BufferSuballocation( const Buffer& buffer, const vk::DeviceSize size ) :
|
||||
BufferSuballocation( buffer->allocate( size ) )
|
||||
{}
|
||||
|
||||
BufferSuballocation::BufferSuballocation( Buffer& buffer, const std::size_t t_size, const std::uint32_t t_align ) :
|
||||
BufferSuballocation( buffer.allocate( t_size, t_align ) )
|
||||
BufferSuballocation::BufferSuballocation( const Buffer& buffer, const std::size_t t_size, const std::uint32_t t_align ) :
|
||||
BufferSuballocation( buffer->allocate( t_size, t_align ) )
|
||||
{}
|
||||
|
||||
} // namespace fgl::engine::memory
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
class SuballocationView;
|
||||
|
||||
struct BufferSuballocationHandle;
|
||||
@@ -30,7 +30,7 @@ namespace fgl::engine::memory
|
||||
|
||||
void flush( vk::DeviceSize beg, vk::DeviceSize end ) const;
|
||||
|
||||
explicit BufferSuballocation( Buffer& buffer, std::size_t t_size, std::uint32_t t_align );
|
||||
explicit BufferSuballocation( const Buffer& buffer, std::size_t t_size, std::uint32_t t_align );
|
||||
|
||||
public:
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace fgl::engine::memory
|
||||
BufferSuballocation() = delete;
|
||||
|
||||
BufferSuballocation( std::shared_ptr< BufferSuballocationHandle > handle );
|
||||
BufferSuballocation( Buffer& buffer, vk::DeviceSize size );
|
||||
BufferSuballocation( const Buffer& buffer, vk::DeviceSize size );
|
||||
|
||||
FGL_DELETE_COPY( BufferSuballocation );
|
||||
|
||||
|
||||
@@ -4,35 +4,40 @@
|
||||
|
||||
#include "BufferSuballocationHandle.hpp"
|
||||
|
||||
#include "Buffer.hpp"
|
||||
#include "BufferHandle.hpp"
|
||||
#include "BufferSuballocation.hpp"
|
||||
#include "assets/transfer/TransferManager.hpp"
|
||||
#include "engine/debug/logging/logging.hpp"
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
vk::Buffer BufferSuballocationHandle::getBuffer() const
|
||||
{
|
||||
return m_buffer.getVkBuffer();
|
||||
return m_parent_buffer->getVkBuffer();
|
||||
}
|
||||
|
||||
BufferSuballocationHandle::
|
||||
BufferSuballocationHandle( Buffer& p_buffer, const vk::DeviceSize offset, const vk::DeviceSize memory_size ) :
|
||||
m_buffer( p_buffer ),
|
||||
BufferSuballocationHandle::BufferSuballocationHandle(
|
||||
const Buffer& p_buffer,
|
||||
const vk::DeviceSize offset,
|
||||
const vk::DeviceSize memory_size,
|
||||
const vk::DeviceSize alignment ) :
|
||||
m_parent_buffer( p_buffer ),
|
||||
m_size( memory_size ),
|
||||
m_offset( offset ),
|
||||
m_ptr( m_buffer.map( *this ) )
|
||||
m_alignment( alignment ),
|
||||
m_ptr( m_parent_buffer->map( *this ) )
|
||||
{
|
||||
// assert( memory_size != 0 && "BufferSuballocation::BufferSuballocation() called with memory_size == 0" );
|
||||
}
|
||||
|
||||
vk::Buffer BufferSuballocationHandle::getVkBuffer() const
|
||||
{
|
||||
return m_buffer.getVkBuffer();
|
||||
return m_parent_buffer->getVkBuffer();
|
||||
}
|
||||
|
||||
BufferSuballocationHandle::~BufferSuballocationHandle()
|
||||
{
|
||||
m_buffer.free( *this );
|
||||
m_parent_buffer->free( *this );
|
||||
}
|
||||
|
||||
vk::BufferCopy BufferSuballocationHandle::
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "BufferHandle.hpp"
|
||||
#include "engine/debug/Track.hpp"
|
||||
|
||||
namespace vk::raii
|
||||
@@ -17,11 +16,11 @@ namespace vk::raii
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
|
||||
struct BufferSuballocationHandle
|
||||
struct BufferSuballocationHandle : public std::enable_shared_from_this< BufferSuballocationHandle >
|
||||
{
|
||||
Buffer& m_buffer;
|
||||
Buffer m_parent_buffer;
|
||||
|
||||
debug::Track< "GPU", "BufferSuballocationHandle" > m_track {};
|
||||
|
||||
@@ -31,27 +30,28 @@ namespace fgl::engine::memory
|
||||
//! Offset within buffer
|
||||
vk::DeviceSize m_offset;
|
||||
|
||||
//! Alignment used when allocating
|
||||
vk::DeviceSize m_alignment;
|
||||
|
||||
void* m_ptr { nullptr };
|
||||
|
||||
bool m_staged { false };
|
||||
|
||||
BufferSuballocationHandle() = delete;
|
||||
BufferSuballocationHandle(
|
||||
const Buffer& p_buffer, vk::DeviceSize offset, vk::DeviceSize memory_size, vk::DeviceSize alignment );
|
||||
|
||||
FGL_DELETE_DEFAULT_CTOR( BufferSuballocationHandle );
|
||||
FGL_DELETE_MOVE( BufferSuballocationHandle );
|
||||
FGL_DELETE_COPY( BufferSuballocationHandle );
|
||||
|
||||
BufferSuballocationHandle( Buffer& p_buffer, vk::DeviceSize offset, vk::DeviceSize memory_size );
|
||||
~BufferSuballocationHandle();
|
||||
|
||||
BufferSuballocationHandle( const BufferSuballocationHandle& ) = delete;
|
||||
BufferSuballocationHandle& operator=( const BufferSuballocationHandle& ) = delete;
|
||||
|
||||
BufferSuballocationHandle( BufferSuballocationHandle&& ) = delete;
|
||||
BufferSuballocationHandle& operator=( BufferSuballocationHandle&& ) = delete;
|
||||
|
||||
[[nodiscard]] vk::Buffer getBuffer() const;
|
||||
[[nodiscard]] vk::Buffer getVkBuffer() const;
|
||||
|
||||
[[nodiscard]] vk::BufferCopy copyRegion( const BufferSuballocationHandle& target, std::size_t offset ) const;
|
||||
|
||||
vk::DeviceSize getOffset() const { return m_offset; }
|
||||
[[nodiscard]] vk::DeviceSize getOffset() const { return m_offset; }
|
||||
|
||||
void copyTo(
|
||||
const vk::raii::CommandBuffer& cmd_buffer,
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace fgl::engine
|
||||
{
|
||||
namespace memory
|
||||
{
|
||||
class Buffer;
|
||||
struct Buffer;
|
||||
}
|
||||
|
||||
//! Single element allocation of T
|
||||
@@ -26,7 +26,7 @@ namespace fgl::engine
|
||||
HostSingleT( HostSingleT&& ) = delete;
|
||||
HostSingleT& operator=( const HostSingleT& ) = delete;
|
||||
|
||||
HostSingleT( memory::Buffer& buffer ) : memory::BufferSuballocation( buffer, sizeof( T ), alignof( T ) ) {}
|
||||
HostSingleT( const memory::Buffer& buffer ) : memory::BufferSuballocation( buffer, sizeof( T ), alignof( T ) ) {}
|
||||
|
||||
HostSingleT& operator=( T& t )
|
||||
{
|
||||
|
||||
@@ -13,12 +13,11 @@ namespace fgl::engine
|
||||
template < memory::is_suballocation Suballocation >
|
||||
class PerFrameSuballocation
|
||||
{
|
||||
memory::Buffer& m_buffer;
|
||||
std::vector< std::unique_ptr< Suballocation > > m_suballocations {};
|
||||
|
||||
public:
|
||||
|
||||
explicit PerFrameSuballocation( memory::Buffer& buffer ) : m_buffer( buffer )
|
||||
explicit PerFrameSuballocation( memory::Buffer& buffer )
|
||||
{
|
||||
m_suballocations.reserve( constants::MAX_FRAMES_IN_FLIGHT );
|
||||
|
||||
@@ -31,9 +30,9 @@ namespace fgl::engine
|
||||
}
|
||||
}
|
||||
|
||||
void setMaxFramesInFlight( std::uint16_t max ) { m_suballocations.resize( max ); }
|
||||
// void setMaxFramesInFlight( std::uint16_t max ) { m_suballocations.resize( max ); }
|
||||
|
||||
Suballocation& operator[]( std::uint16_t index )
|
||||
Suballocation& operator[]( std::size_t index )
|
||||
{
|
||||
assert( m_suballocations.size() >= index );
|
||||
assert( m_suballocations[ index ] );
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#include "BufferVector.hpp"
|
||||
|
||||
#include "engine/assets/transfer/TransferManager.hpp"
|
||||
#include "engine/memory/buffers/Buffer.hpp"
|
||||
#include "engine/memory/buffers/BufferHandle.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
@@ -13,10 +14,10 @@ namespace fgl::engine::memory
|
||||
constexpr std::uint32_t min_capacity { 1024 };
|
||||
|
||||
[[nodiscard]] BufferVector::BufferVector( Buffer& buffer, std::uint32_t count, std::uint32_t stride ) :
|
||||
BufferSuballocation( buffer.allocate( std::max( count, min_capacity ) * stride, stride ) ),
|
||||
BufferSuballocation( buffer->allocate( std::max( count, min_capacity ) * stride, stride ) ),
|
||||
m_count( count ),
|
||||
m_stride( stride ),
|
||||
m_capacity( std::max( count, min_capacity ) )
|
||||
m_capacity( std::max( count, min_capacity ) ),
|
||||
m_stride( stride )
|
||||
{
|
||||
FGL_ASSERT( m_stride > 0, "Stride was not greater then zero" );
|
||||
FGL_ASSERT(
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
class Buffer;
|
||||
|
||||
//! Number of spares to allocate when resizing beyond the current capacity + current spare
|
||||
constexpr std::uint32_t SPARE_ALLOCATION_COUNT { 16 };
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
namespace fgl::engine::memory
|
||||
{
|
||||
class Buffer;
|
||||
struct Buffer;
|
||||
}
|
||||
|
||||
namespace fgl::engine
|
||||
@@ -31,6 +31,7 @@ namespace fgl::engine
|
||||
// assert( count != 0 && "BufferSuballocationVector::BufferSuballocationVector() called with count == 0" );
|
||||
}
|
||||
|
||||
FGL_DELETE_DEFAULT_CTOR( DeviceVector );
|
||||
FGL_DELETE_COPY( DeviceVector );
|
||||
FGL_DEFAULT_MOVE( DeviceVector );
|
||||
|
||||
@@ -43,9 +44,6 @@ namespace fgl::engine
|
||||
DeviceVector( buffer, static_cast< std::uint32_t >( data.size() ) )
|
||||
{
|
||||
memory::TransferManager::getInstance().copyToVector< T, DeviceVector< T > >( data, *this );
|
||||
|
||||
log::debug(
|
||||
"Allocated device vector of size: {}, With stride: {} at offset {}", size(), stride(), m_offset );
|
||||
}
|
||||
|
||||
// void resize( const std::size_t new_size ) { BufferVector::resize( new_size ); }
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace fgl::engine
|
||||
* @tparam CType
|
||||
*/
|
||||
template < CoordinateSpace CType >
|
||||
class FGL_PACKED SimplePlane
|
||||
class SimplePlane
|
||||
{
|
||||
NormalVector m_vector;
|
||||
float m_distance;
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <glm/vec3.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "../rotation/QuatRotation.hpp"
|
||||
#include "engine/primitives/CoordinateSpace.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
@@ -52,15 +51,13 @@ namespace fgl::engine
|
||||
NormalVector( const NormalVector& other ) = default;
|
||||
NormalVector& operator=( const NormalVector& other ) = default;
|
||||
|
||||
const glm::vec3& vec() const { return static_cast< const glm::vec3& >( *this ); }
|
||||
[[nodiscard]] const glm::vec3& vec() const { return static_cast< const glm::vec3& >( *this ); }
|
||||
|
||||
glm::vec3& vec() { return static_cast< glm::vec3& >( *this ); }
|
||||
|
||||
Vector operator*( const float scalar ) const;
|
||||
Vector operator*( float scalar ) const;
|
||||
|
||||
NormalVector operator-() const { return NormalVector( -static_cast< glm::vec3 >( *this ) ); }
|
||||
|
||||
explicit operator glm::vec3() const { return static_cast< glm::vec3 >( *this ); }
|
||||
};
|
||||
|
||||
} // namespace fgl::engine
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "engine/debug/timing/FlameGraph.hpp"
|
||||
#include "engine/rendering/pipelines/v2/Pipeline.hpp"
|
||||
#include "engine/rendering/pipelines/v2/PipelineBuilder.hpp"
|
||||
#include "memory/buffers/BufferHandle.hpp"
|
||||
|
||||
namespace fgl::engine
|
||||
{
|
||||
@@ -90,13 +91,13 @@ namespace fgl::engine
|
||||
auto& model_buffers { getModelBuffers() };
|
||||
|
||||
const std::vector< vk::Buffer > vert_buffers {
|
||||
model_buffers.m_vertex_buffer.getVkBuffer(),
|
||||
model_buffers.m_vertex_buffer->getVkBuffer(),
|
||||
model_buffers.m_generated_instance_info[ info.in_flight_idx ].getVkBuffer()
|
||||
};
|
||||
|
||||
command_buffer->bindVertexBuffers(
|
||||
0, vert_buffers, { 0, model_buffers.m_generated_instance_info[ info.in_flight_idx ].getOffset() } );
|
||||
command_buffer->bindIndexBuffer( model_buffers.m_index_buffer.getVkBuffer(), 0, vk::IndexType::eUint32 );
|
||||
command_buffer->bindIndexBuffer( model_buffers.m_index_buffer->getVkBuffer(), 0, vk::IndexType::eUint32 );
|
||||
|
||||
command_buffer->drawIndexedIndirect(
|
||||
info.m_commands.getVkBuffer(),
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace fgl::engine
|
||||
|
||||
namespace memory
|
||||
{
|
||||
class Buffer;
|
||||
class BufferHandle;
|
||||
}
|
||||
|
||||
struct FrameInfo;
|
||||
|
||||
Reference in New Issue
Block a user