@@ -224,6 +224,11 @@ auto RenderGraph::MoveFrom(RenderGraphNode::Type type, std::size_t resource_node
224224 return invalid_index;
225225 } break ;
226226 }
227+
228+ if (!name.empty ()) {
229+ m_BlackBoard[type].emplace (name, new_handle);
230+ }
231+
227232 return new_handle;
228233}
229234
@@ -440,11 +445,134 @@ void RenderGraph::RetireNodes() noexcept {
440445 const auto & retired_resource = m_RetiredNodes.front ();
441446 const auto & [fence, last_value] = retired_resource.last_fence_value ;
442447 if (latest_fence_values.at (fence) >= last_value) {
448+ RecycleTransientResource (retired_resource.node .get ());
443449 m_RetiredNodes.pop_front ();
444450 } else {
445451 break ;
446452 }
447453 }
454+
455+ EvictStalePoolEntries ();
456+ }
457+
458+ static auto buffer_pool_key (const gfx::GPUBufferDesc& desc) -> std::size_t {
459+ return utils::combine_hash (std::array{
460+ utils::hash (desc.element_size ),
461+ utils::hash (desc.element_count ),
462+ utils::hash (desc.usages ),
463+ });
464+ }
465+
466+ static bool buffer_pool_match (const gfx::GPUBufferDesc& a, const gfx::GPUBufferDesc& b) {
467+ return a.element_size == b.element_size &&
468+ a.element_count == b.element_count &&
469+ a.usages == b.usages ;
470+ }
471+
472+ static auto texture_pool_key (const gfx::TextureDesc& desc) -> std::size_t {
473+ return utils::combine_hash (std::array{
474+ utils::hash (desc.width ),
475+ utils::hash (desc.height ),
476+ utils::hash (static_cast <std::uint16_t >(desc.depth )),
477+ utils::hash (static_cast <std::uint16_t >(desc.array_size )),
478+ utils::hash (desc.format ),
479+ utils::hash (static_cast <std::uint16_t >(desc.mip_levels )),
480+ utils::hash (desc.usages ),
481+ });
482+ }
483+
484+ static bool texture_pool_match (const gfx::TextureDesc& a, const gfx::TextureDesc& b) {
485+ return a.width == b.width &&
486+ a.height == b.height &&
487+ a.depth == b.depth &&
488+ a.array_size == b.array_size &&
489+ a.format == b.format &&
490+ a.mip_levels == b.mip_levels &&
491+ a.clear_value .has_value () == b.clear_value .has_value () &&
492+ a.usages == b.usages ;
493+ }
494+
495+ auto RenderGraph::AcquireTransientBuffer (const gfx::GPUBufferDesc& desc) -> std::shared_ptr<gfx::GPUBuffer> {
496+ const auto key = buffer_pool_key (desc);
497+ auto range = m_TransientPool.buffers .equal_range (key);
498+ for (auto it = range.first ; it != range.second ; ++it) {
499+ if (buffer_pool_match (it->second .desc , desc)) {
500+ auto resource = std::move (it->second .resource );
501+ m_TransientPool.buffers .erase (it);
502+ m_Logger->trace (" Reused transient buffer from pool: {}" , desc.name );
503+ return resource;
504+ }
505+ }
506+ return m_Device.CreateGPUBuffer (desc);
507+ }
508+
509+ auto RenderGraph::AcquireTransientTexture (const gfx::TextureDesc& desc) -> std::shared_ptr<gfx::Texture> {
510+ const auto key = texture_pool_key (desc);
511+ auto range = m_TransientPool.textures .equal_range (key);
512+ for (auto it = range.first ; it != range.second ; ++it) {
513+ if (texture_pool_match (it->second .desc , desc)) {
514+ auto resource = std::move (it->second .resource );
515+ m_TransientPool.textures .erase (it);
516+ m_Logger->trace (" Reused transient texture from pool: {}" , desc.name );
517+ return resource;
518+ }
519+ }
520+ return m_Device.CreateTexture (desc);
521+ }
522+
523+ void RenderGraph::RecycleTransientResource (RenderGraphNode* node) noexcept {
524+ if (!node->IsResourceNode ()) return ;
525+
526+ auto * resource_node = static_cast <ResourceNode*>(node);
527+ if (resource_node->m_IsImported || !resource_node->m_Resource ) return ;
528+
529+ switch (node->GetType ()) {
530+ case RenderGraphNode::Type::GPUBuffer: {
531+ auto * buffer_node = static_cast <GPUBufferNode*>(node);
532+ if (buffer_node->m_MoveFromNode || buffer_node->m_MoveToNode ) return ;
533+ auto resource = std::static_pointer_cast<gfx::GPUBuffer>(resource_node->m_Resource );
534+ m_TransientPool.buffers .emplace (
535+ buffer_pool_key (buffer_node->GetDesc ()),
536+ TransientResourcePool::CachedBuffer{
537+ .desc = buffer_node->GetDesc (),
538+ .resource = std::move (resource),
539+ .last_used_frame = m_FrameIndex,
540+ });
541+ resource_node->m_Resource = nullptr ;
542+ } break ;
543+ case RenderGraphNode::Type::Texture: {
544+ auto * texture_node = static_cast <TextureNode*>(node);
545+ if (texture_node->m_MoveFromNode || texture_node->m_MoveToNode ) return ;
546+ auto resource = std::static_pointer_cast<gfx::Texture>(resource_node->m_Resource );
547+ m_TransientPool.textures .emplace (
548+ texture_pool_key (texture_node->GetDesc ()),
549+ TransientResourcePool::CachedTexture{
550+ .desc = texture_node->GetDesc (),
551+ .resource = std::move (resource),
552+ .last_used_frame = m_FrameIndex,
553+ });
554+ resource_node->m_Resource = nullptr ;
555+ } break ;
556+ default :
557+ break ;
558+ }
559+ }
560+
561+ void RenderGraph::EvictStalePoolEntries () noexcept {
562+ for (auto it = m_TransientPool.buffers .begin (); it != m_TransientPool.buffers .end ();) {
563+ if (m_FrameIndex - it->second .last_used_frame > TransientResourcePool::max_unused_frames) {
564+ it = m_TransientPool.buffers .erase (it);
565+ } else {
566+ ++it;
567+ }
568+ }
569+ for (auto it = m_TransientPool.textures .begin (); it != m_TransientPool.textures .end ();) {
570+ if (m_FrameIndex - it->second .last_used_frame > TransientResourcePool::max_unused_frames) {
571+ it = m_TransientPool.textures .erase (it);
572+ } else {
573+ ++it;
574+ }
575+ }
448576}
449577
450578auto RenderGraph::ToDot () const noexcept -> std::pmr::string {
0 commit comments