diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-10-01 06:48:48 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-10-01 06:48:48 +0000 |
| commit | fac60b7f00553f6f76cf0543bb1a861d1a58c092 (patch) | |
| tree | 2729cd8bbdb66d7c99233a8a3a1543fdb8ea7b6e /Graphics/GraphicsEngineVulkan | |
| parent | Some minor updates to resource lifetime management in Vk backend + comments (diff) | |
| download | DiligentCore-fac60b7f00553f6f76cf0543bb1a861d1a58c092.tar.gz DiligentCore-fac60b7f00553f6f76cf0543bb1a861d1a58c092.zip | |
Multiple minor updates to resource lifetime management system in Vk backend
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
17 files changed, 171 insertions, 160 deletions
diff --git a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h index f8e406d2..04ba603f 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h @@ -57,6 +57,10 @@ public: void DestroyPools(); +#ifdef DEVELOPMENT + int32_t GetAllocatedPoolCount()const{return m_AllocatedPoolCounter;} +#endif + private: RenderDeviceVkImpl& m_DeviceVkImpl; const std::string m_Name; diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h index 1f52605d..3ff54944 100644 --- a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h +++ b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h @@ -145,11 +145,12 @@ public: DescriptorPoolManager& operator = (DescriptorPoolManager&&) = delete; VulkanUtilities::DescriptorPoolWrapper GetPool(const char* DebugName); - void FreePool(VulkanUtilities::DescriptorPoolWrapper&& Pool); + void DisposePool(VulkanUtilities::DescriptorPoolWrapper&& Pool, Uint64 QueueMask); + + RenderDeviceVkImpl& GetDeviceVkImpl() {return m_DeviceVkImpl;} protected: - friend class DynamicDescriptorSetAllocator; - VulkanUtilities::DescriptorPoolWrapper CreateDescriptorPool(const char* DebugName); + VulkanUtilities::DescriptorPoolWrapper CreateDescriptorPool(const char* DebugName)const; RenderDeviceVkImpl& m_DeviceVkImpl; const std::string m_PoolName; @@ -161,14 +162,17 @@ protected: std::mutex m_Mutex; std::deque< VulkanUtilities::DescriptorPoolWrapper > m_Pools; +private: + void FreePool(VulkanUtilities::DescriptorPoolWrapper&& Pool); + #ifdef DEVELOPMENT std::atomic_int32_t m_AllocatedPoolCounter = 0; #endif }; -// The class allocates descriptors from the main descriptor pool. -// Descriptors can be released and returned to the pool +// The class allocates descriptor sets from the main descriptor pool. +// Descriptors sets can be released and returned to the pool class DescriptorSetAllocator : public DescriptorPoolManager { public: @@ -192,7 +196,7 @@ private: // DynamicDescriptorSetAllocator manages dynamic descriptor sets. It first requests descriptor pool from // the global manager and allocates descriptor sets from this pool. When space in the pool is exhausted, // the class requests a new pool. -// The class is not thread-safe as device contexts must not be used in multiple threads at the same time. +// The class is not thread-safe as device contexts must not be used in multiple threads simultaneously. // All allocated pools are recycled at the end of every frame. // ____________________________________________________________________________ // | | @@ -214,17 +218,22 @@ class DynamicDescriptorSetAllocator { public: DynamicDescriptorSetAllocator(DescriptorPoolManager& PoolMgr, std::string Name) : - m_PoolMgr(PoolMgr), - m_Name(std::move(Name)) + m_GlobalPoolMgr(PoolMgr), + m_Name (std::move(Name)) {} ~DynamicDescriptorSetAllocator(); VkDescriptorSet Allocate(VkDescriptorSetLayout SetLayout, const char* DebugName); + + // Releases all allocated pools that are later returned to the global pool manager. + // As global pool manager is hosted by the render device, the allocator can + // be destroyed before the pools are actually returned to the global pool manager. void ReleasePools(Uint64 QueueMask); + size_t GetAllocatedPoolCount()const{return m_AllocatedPools.size();} private: - DescriptorPoolManager& m_PoolMgr; + DescriptorPoolManager& m_GlobalPoolMgr; const std::string m_Name; std::vector<VulkanUtilities::DescriptorPoolWrapper> m_AllocatedPools; size_t m_PeakPoolCount = 0; diff --git a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h index b82ba8be..b8860e90 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -117,11 +117,6 @@ public: m_SignalSemaphores.push_back(Semaphore); } - ///// Clears the state caches. This function is called once per frame - ///// (before present) to release all outstanding objects - ///// that are only kept alive by references in the cache - //void ClearShaderStateCache(); - void UpdateBufferRegion(class BufferVkImpl* pBuffVk, Uint64 DstOffset, Uint64 NumBytes, VkBuffer vkSrcBuffer, Uint64 SrcOffset); void UpdateBufferRegion(class BufferVkImpl* pBuffVk, const void* pData, Uint64 DstOffset, Uint64 NumBytes); @@ -250,9 +245,9 @@ private: Uint64 m_SubmittedBuffersCmdQueueMask = 0; // Semaphores are not owned by the command context - std::vector<VkSemaphore> m_WaitSemaphores; - std::vector<VkPipelineStageFlags> m_WaitDstStageMasks; - std::vector<VkSemaphore> m_SignalSemaphores; + std::vector<VkSemaphore> m_WaitSemaphores; + std::vector<VkPipelineStageFlags> m_WaitDstStageMasks; + std::vector<VkSemaphore> m_SignalSemaphores; // List of fences to signal next time the command context is flushed std::vector<std::pair<Uint64, RefCntAutoPtr<IFence> > > m_PendingFences; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h b/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h index 4282bd35..9182c599 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanDynamicHeap.h @@ -177,7 +177,7 @@ class VulkanDynamicHeap { public: VulkanDynamicHeap(VulkanDynamicMemoryManager& DynamicMemMgr, std::string HeapName, Uint32 PageSize) : - m_DynamicMemMgr(DynamicMemMgr), + m_GlobalDynamicMemMgr(DynamicMemMgr), m_HeapName(std::move(HeapName)), m_MasterBlockSize(PageSize) {} @@ -190,8 +190,12 @@ public: ~VulkanDynamicHeap(); VulkanDynamicAllocation Allocate(Uint32 SizeInBytes, Uint32 Alignment); + + // Releases all master blocks that are later returned to the global dynamic memory manager. // CmdQueueMask indicates which command queues the allocations from this heap were used - // with during the last frame + // with during the last frame. + // As global dynamic memory manager is hosted by the render device, the dynamic heap can + // be destroyed before the blocks are actually returned to the global dynamic memory manager. void ReleaseMasterBlocks(RenderDeviceVkImpl& DeviceVkImpl, Uint64 CmdQueueMask); using OffsetType = VulkanDynamicMemoryManager::OffsetType; @@ -201,7 +205,7 @@ public: size_t GetAllocatedMasterBlockCount()const {return m_MasterBlocks.size();} private: - VulkanDynamicMemoryManager& m_DynamicMemMgr; + VulkanDynamicMemoryManager& m_GlobalDynamicMemMgr; const std::string m_HeapName; std::vector<MasterBlock> m_MasterBlocks; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUploadHeap.h b/Graphics/GraphicsEngineVulkan/include/VulkanUploadHeap.h index 67c118c5..eadce104 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUploadHeap.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUploadHeap.h @@ -93,7 +93,10 @@ public: ~VulkanUploadHeap(); VulkanUploadAllocation Allocate(size_t SizeInBytes, size_t Alignment); - // Releases all allocated pages that are returned to the global memory manager by the release queues + + // Releases all allocated pages that are later returned to the global memory manager by the release queues. + // As global memory manager is hosted by the render device, the upload heap can be destroyed before the + // pages are actually returned to the manager. void ReleaseAllocatedPages(Uint64 CmdQueueMask); size_t GetStalePagesCount()const @@ -140,7 +143,7 @@ private: size_t m_CurrAllocatedSize = 0; size_t m_PeakAllocatedSize = 0; - UploadPageInfo CreateNewPage(VkDeviceSize SizeInBytes); + UploadPageInfo CreateNewPage(VkDeviceSize SizeInBytes)const; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h index f5e6f3c1..3143a0ac 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBuffer.h @@ -32,10 +32,10 @@ namespace VulkanUtilities { public: VulkanCommandBuffer()noexcept{} - VulkanCommandBuffer (const VulkanCommandBuffer&) = delete; - VulkanCommandBuffer (VulkanCommandBuffer&&) = delete; - VulkanCommandBuffer& operator = (const VulkanCommandBuffer&) = delete; - VulkanCommandBuffer& operator = (VulkanCommandBuffer&&) = delete; + VulkanCommandBuffer (const VulkanCommandBuffer&) = delete; + VulkanCommandBuffer ( VulkanCommandBuffer&&) = delete; + VulkanCommandBuffer& operator = (const VulkanCommandBuffer&) = delete; + VulkanCommandBuffer& operator = ( VulkanCommandBuffer&&) = delete; void ClearColorImage(VkImage Image, const VkClearColorValue& Color, const VkImageSubresourceRange& Subresource) { diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h index 25318763..41e3cdf3 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanCommandBufferPool.h @@ -36,18 +36,19 @@ namespace VulkanUtilities class VulkanCommandBufferPool { public: - VulkanCommandBufferPool(std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> LogicalDevice, - uint32_t queueFamilyIndex, - VkCommandPoolCreateFlags flags); + VulkanCommandBufferPool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice, + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags); - VulkanCommandBufferPool (const VulkanCommandBufferPool&) = delete; - VulkanCommandBufferPool (VulkanCommandBufferPool&&) = delete; - VulkanCommandBufferPool& operator = (const VulkanCommandBufferPool&) = delete; - VulkanCommandBufferPool& operator = (VulkanCommandBufferPool&&) = delete; + VulkanCommandBufferPool (const VulkanCommandBufferPool&) = delete; + VulkanCommandBufferPool ( VulkanCommandBufferPool&&) = delete; + VulkanCommandBufferPool& operator = (const VulkanCommandBufferPool&) = delete; + VulkanCommandBufferPool& operator = ( VulkanCommandBufferPool&&) = delete; ~VulkanCommandBufferPool(); VkCommandBuffer GetCommandBuffer(const char* DebugName = ""); + // The GPU must have finished with the command buffer being returned to the pool void FreeCommandBuffer(VkCommandBuffer&& CmdBuffer); CommandPoolWrapper&& Release(); @@ -58,7 +59,7 @@ namespace VulkanUtilities private: // Shared point to logical device must be defined before the command pool - std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> m_LogicalDevice; + std::shared_ptr<const VulkanLogicalDevice> m_LogicalDevice; CommandPoolWrapper m_CmdPool; std::mutex m_Mutex; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h index 4c79a868..d43698ee 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanFencePool.h @@ -34,7 +34,7 @@ namespace VulkanUtilities class VulkanFencePool { public: - VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice); + VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice)noexcept; VulkanFencePool (const VulkanFencePool&) = delete; VulkanFencePool (VulkanFencePool&&) = delete; @@ -43,12 +43,12 @@ namespace VulkanUtilities ~VulkanFencePool(); - VulkanUtilities::FenceWrapper GetFence(); - void DisposeFence(VulkanUtilities::FenceWrapper&& Fence); + FenceWrapper GetFence(); + void DisposeFence(FenceWrapper&& Fence); private: // Shared pointer to logical device must be declared before fences std::shared_ptr<const VulkanLogicalDevice> m_LogicalDevice; - std::vector<VulkanUtilities::FenceWrapper> m_Fences; + std::vector<FenceWrapper> m_Fences; }; } diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h index 9a60a7fd..56cab131 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanInstance.h @@ -32,10 +32,10 @@ namespace VulkanUtilities class VulkanInstance : public std::enable_shared_from_this<VulkanInstance> { public: - VulkanInstance (const VulkanInstance&) = delete; - VulkanInstance (VulkanInstance&&) = delete; - VulkanInstance& operator = (const VulkanInstance&) = delete; - VulkanInstance& operator = (VulkanInstance&&) = delete; + VulkanInstance (const VulkanInstance&) = delete; + VulkanInstance ( VulkanInstance&&) = delete; + VulkanInstance& operator = (const VulkanInstance&) = delete; + VulkanInstance& operator = ( VulkanInstance&&) = delete; static std::shared_ptr<VulkanInstance> Create(bool EnableValidation, uint32_t GlobalExtensionCount, diff --git a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp index e4a16061..a02c0545 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandPoolManager.cpp @@ -55,12 +55,12 @@ VulkanUtilities::CommandPoolWrapper CommandPoolManager::AllocateCommandPool(cons if(CmdPool == VK_NULL_HANDLE) { VkCommandPoolCreateInfo CmdPoolCI = {}; - CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - CmdPoolCI.pNext = nullptr; + CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + CmdPoolCI.pNext = nullptr; CmdPoolCI.queueFamilyIndex = m_QueueFamilyIndex; - CmdPoolCI.flags = m_CmdPoolFlags; + CmdPoolCI.flags = m_CmdPoolFlags; CmdPool = LogicalDevice.CreateCommandPool(CmdPoolCI); - VERIFY_EXPR(CmdPool != VK_NULL_HANDLE); + DEV_CHECK_ERR(CmdPool != VK_NULL_HANDLE, "Failed to create Vulkan command pool"); } LogicalDevice.ResetCommandPool(CmdPool); diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp index c10b8a14..20d9fac6 100644 --- a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp @@ -39,7 +39,7 @@ void DescriptorSetAllocation::Release() } } -VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPool(const char* DebugName) +VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPool(const char* DebugName)const { VkDescriptorPoolCreateInfo PoolCI = {}; PoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -47,10 +47,10 @@ VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPo // VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT specifies that descriptor sets can // return their individual allocations to the pool, i.e. all of vkAllocateDescriptorSets, // vkFreeDescriptorSets, and vkResetDescriptorPool are allowed. (13.2.3) - PoolCI.flags = m_AllowFreeing ? VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT : 0; - PoolCI.maxSets = m_MaxSets; + PoolCI.flags = m_AllowFreeing ? VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT : 0; + PoolCI.maxSets = m_MaxSets; PoolCI.poolSizeCount = static_cast<uint32_t>(m_PoolSizes.size()); - PoolCI.pPoolSizes = m_PoolSizes.data(); + PoolCI.pPoolSizes = m_PoolSizes.data(); return m_DeviceVkImpl.GetLogicalDevice().CreateDescriptorPool(PoolCI, DebugName); } @@ -78,6 +78,44 @@ VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::GetPool(const char } } +void DescriptorPoolManager::DisposePool(VulkanUtilities::DescriptorPoolWrapper&& Pool, Uint64 QueueMask) +{ + class DescriptorPoolDeleter + { + public: + DescriptorPoolDeleter(DescriptorPoolManager& _PoolMgr, + VulkanUtilities::DescriptorPoolWrapper&& _Pool) noexcept : + PoolMgr (&_PoolMgr), + Pool (std::move(_Pool)) + {} + + DescriptorPoolDeleter (const DescriptorPoolDeleter&) = delete; + DescriptorPoolDeleter& operator = (const DescriptorPoolDeleter&) = delete; + DescriptorPoolDeleter& operator = ( DescriptorPoolDeleter&&)= delete; + + DescriptorPoolDeleter(DescriptorPoolDeleter&& rhs)noexcept : + PoolMgr (rhs.PoolMgr), + Pool (std::move(rhs.Pool)) + { + rhs.PoolMgr = nullptr; + } + + ~DescriptorPoolDeleter() + { + if (PoolMgr!=nullptr) + { + PoolMgr->FreePool(std::move(Pool)); + } + } + + private: + DescriptorPoolManager* PoolMgr; + VulkanUtilities::DescriptorPoolWrapper Pool; + }; + + m_DeviceVkImpl.SafeReleaseDeviceObject(DescriptorPoolDeleter{*this, std::move(Pool)}, QueueMask); +} + void DescriptorPoolManager::FreePool(VulkanUtilities::DescriptorPoolWrapper&& Pool) { std::lock_guard<std::mutex> Lock(m_Mutex); @@ -95,11 +133,11 @@ static VkDescriptorSet AllocateDescriptorSet(const VulkanUtilities::VulkanLogica const char* DebugName) { VkDescriptorSetAllocateInfo DescrSetAllocInfo = {}; - DescrSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - DescrSetAllocInfo.pNext = nullptr; - DescrSetAllocInfo.descriptorPool = Pool; + DescrSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + DescrSetAllocInfo.pNext = nullptr; + DescrSetAllocInfo.descriptorPool = Pool; DescrSetAllocInfo.descriptorSetCount = 1; - DescrSetAllocInfo.pSetLayouts = &SetLayout; + DescrSetAllocInfo.pSetLayouts = &SetLayout; // Descriptor pools are externally synchronized, meaning that the application must not allocate // and/or free descriptor sets from the same pool in multiple threads simultaneously (13.2.3) return LogicalDevice.AllocateVkDescriptorSet(DescrSetAllocInfo, DebugName); @@ -135,7 +173,7 @@ DescriptorSetAllocation DescriptorSetAllocator::Allocate(Uint64 CommandQueueMask auto& NewPool = m_Pools.front(); auto Set = AllocateDescriptorSet(LogicalDevice, NewPool, SetLayout, ""); - VERIFY(Set != VK_NULL_HANDLE, "Failed to allocate descriptor set"); + DEV_CHECK_ERR(Set != VK_NULL_HANDLE, "Failed to allocate descriptor set"); return {Set, NewPool, CommandQueueMask, *this }; } @@ -188,7 +226,7 @@ void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptor VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout SetLayout, const char* DebugName) { VkDescriptorSet set = VK_NULL_HANDLE; - const auto& LogicalDevice = m_PoolMgr.m_DeviceVkImpl.GetLogicalDevice(); + const auto& LogicalDevice = m_GlobalPoolMgr.GetDeviceVkImpl().GetLogicalDevice(); if (!m_AllocatedPools.empty()) { set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); @@ -196,7 +234,7 @@ VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout Se if (set == VK_NULL_HANDLE) { - m_AllocatedPools.emplace_back(m_PoolMgr.GetPool("Dynamic Descriptor Pool")); + m_AllocatedPools.emplace_back(m_GlobalPoolMgr.GetPool("Dynamic Descriptor Pool")); set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); } @@ -205,42 +243,9 @@ VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout Se void DynamicDescriptorSetAllocator::ReleasePools(Uint64 QueueMask) { - class DescriptorPoolDeleter - { - public: - DescriptorPoolDeleter(DescriptorPoolManager& _PoolMgr, - VulkanUtilities::DescriptorPoolWrapper&& _Pool) noexcept : - PoolMgr (&_PoolMgr), - Pool (std::move(_Pool)) - {} - - DescriptorPoolDeleter (const DescriptorPoolDeleter&) = delete; - DescriptorPoolDeleter& operator = (const DescriptorPoolDeleter&) = delete; - DescriptorPoolDeleter& operator = ( DescriptorPoolDeleter&&)= delete; - - DescriptorPoolDeleter(DescriptorPoolDeleter&& rhs)noexcept : - PoolMgr (rhs.PoolMgr), - Pool (std::move(rhs.Pool)) - { - rhs.PoolMgr = nullptr; - } - - ~DescriptorPoolDeleter() - { - if (PoolMgr!=nullptr) - { - PoolMgr->FreePool(std::move(Pool)); - } - } - - private: - DescriptorPoolManager* PoolMgr; - VulkanUtilities::DescriptorPoolWrapper Pool; - }; - for(auto& Pool : m_AllocatedPools) { - m_PoolMgr.m_DeviceVkImpl.SafeReleaseDeviceObject(DescriptorPoolDeleter{m_PoolMgr, std::move(Pool)}, QueueMask); + m_GlobalPoolMgr.DisposePool(std::move(Pool), QueueMask); } m_PeakPoolCount = std::max(m_PeakPoolCount, m_AllocatedPools.size()); m_AllocatedPools.clear(); diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 3d7d0658..84a47bd7 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -759,13 +759,19 @@ namespace Diligent // Release resources used by the context during this frame. - // Upload heap returns all allocated pages to the global memory manager + // Upload heap returns all allocated pages to the global memory manager. + // Note: as global memory manager is hosted by the render device, the upload heap can be destroyed + // before the pages are actually returned to the manager. m_UploadHeap.ReleaseAllocatedPages(m_SubmittedBuffersCmdQueueMask); - // Dynamic heap returns all allocated master blocks to global dynamic memory manager + // Dynamic heap returns all allocated master blocks to the global dynamic memory manager. + // Note: as global dynamic memory manager is hosted by the render device, the dynamic heap can + // be destroyed before the blocks are actually returned to the global dynamic memory manager. m_DynamicHeap.ReleaseMasterBlocks(DeviceVkImpl, m_SubmittedBuffersCmdQueueMask); - // Dynamic descriptor set allocator returns all allocated pools to global dynamic descriptor pool manager + // Dynamic descriptor set allocator returns all allocated pools to the global dynamic descriptor pool manager. + // Note: as global pool manager is hosted by the render device, the allocator can + // be destroyed before the pools are actually returned to the global pool manager. m_DynamicDescrSetAllocator.ReleasePools(m_SubmittedBuffersCmdQueueMask); if (m_bIsDeferred) @@ -1408,26 +1414,6 @@ namespace Diligent return; } - // First execute commands in this context - - // Note that not discarding resources when flushing the context does not help in case of multiple - // deferred contexts, and resources must not be released until the command list is executed via - // immediate context. - - // Next Cmd Buff| Next Fence | Deferred Context 1 | Deferred Contex 2 | Immediate Context - // | | | | - // N | F | | | - // | | Draw(ResourceX) | | - // | | Release(ResourceX) | Draw(ResourceY) | - // | | - {N, ResourceX} -> Stale Objs | Release(ResourceY) | - // | | | - {N, ResourceY} -> Stale Objs | - // | | | | ExecuteCmdList(CmdList1) - // | | | | {F, ResourceX}-> Release queue - // | | | | {F, ResourceY}-> Release queue - // N+1 | F+1 | | | - // | | | | ExecuteCmdList(CmdList2) - // | | | | - ResourceY is in release queue - // | | | | Flush(); InvalidateState(); @@ -1439,9 +1425,10 @@ namespace Diligent VERIFY(vkCmdBuff != VK_NULL_HANDLE, "Trying to execute empty command buffer"); VERIFY_EXPR(pDeferredCtx); VkSubmitInfo SubmitInfo = {}; - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; + SubmitInfo.pCommandBuffers = &vkCmdBuff; auto pDeviceVkImpl = m_pDevice.RawPtr<RenderDeviceVkImpl>(); VERIFY_EXPR(m_PendingFences.empty()); auto pDeferredCtxVkImpl = pDeferredCtx.RawPtr<DeviceContextVkImpl>(); diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 16c267df..f29dfa3c 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -139,6 +139,9 @@ RenderDeviceVkImpl::~RenderDeviceVkImpl() ReleaseStaleResources(true); + VERIFY(m_TransientCmdPoolMgr.GetAllocatedPoolCount() == 0, "All allocated transient command pools must have been released now. If there are outstanding references to the pools in release queues, the app will crash when CommandPoolManager::FreeCommandPool() is called."); + + // Immediately destroys all command pools m_TransientCmdPoolMgr.DestroyPools(); // We must destroy command queues explicitly prior to releasing Vulkan device @@ -159,13 +162,13 @@ void RenderDeviceVkImpl::AllocateTransientCmdPool(VulkanUtilities::CommandPoolWr // Allocate command buffer from the cmd pool VkCommandBufferAllocateInfo BuffAllocInfo = {}; - BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - BuffAllocInfo.pNext = nullptr; - BuffAllocInfo.commandPool = CmdPool; - BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + BuffAllocInfo.pNext = nullptr; + BuffAllocInfo.commandPool = CmdPool; + BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; BuffAllocInfo.commandBufferCount = 1; vkCmdBuff = m_LogicalVkDevice->AllocateVkCommandBuffer(BuffAllocInfo); - VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); + DEV_CHECK_ERR(vkCmdBuff != VK_NULL_HANDLE, "Failed to allocate Vulkan command buffer"); VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; CmdBuffBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -174,7 +177,8 @@ void RenderDeviceVkImpl::AllocateTransientCmdPool(VulkanUtilities::CommandPoolWr // submitted once, and the command buffer will be reset // and recorded again between each submission. CmdBuffBeginInfo.pInheritanceInfo = nullptr; // Ignored for a primary command buffer - vkBeginCommandBuffer(vkCmdBuff, &CmdBuffBeginInfo); + auto err = vkBeginCommandBuffer(vkCmdBuff, &CmdBuffBeginInfo); + DEV_CHECK_ERR(err == VK_SUCCESS, "vkBeginCommandBuffer() failed"); } @@ -183,12 +187,12 @@ void RenderDeviceVkImpl::ExecuteAndDisposeTransientCmdBuff(Uint32 QueueIndex, Vk VERIFY_EXPR(vkCmdBuff != VK_NULL_HANDLE); auto err = vkEndCommandBuffer(vkCmdBuff); - VERIFY(err == VK_SUCCESS, "Failed to end command buffer"); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to end command buffer"); VkSubmitInfo SubmitInfo = {}; - SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; SubmitInfo.commandBufferCount = 1; - SubmitInfo.pCommandBuffers = &vkCmdBuff; + SubmitInfo.pCommandBuffers = &vkCmdBuff; // We MUST NOT discard stale objects when executing transient command buffer, // otherwise a resource can be destroyed while still being used by the GPU: diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp index 3e1db532..83a36b34 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanDynamicHeap.cpp @@ -206,7 +206,7 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A if(SizeInBytes > m_MasterBlockSize/2) { // Allocate directly from the memory manager - auto MasterBlock = m_DynamicMemMgr.AllocateMasterBlock(SizeInBytes, Alignment); + auto MasterBlock = m_GlobalDynamicMemMgr.AllocateMasterBlock(SizeInBytes, Alignment); if (MasterBlock.UnalignedOffset != InvalidOffset) { AlignedOffset = Align(MasterBlock.UnalignedOffset, size_t{Alignment}); @@ -219,7 +219,7 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A { if (m_CurrOffset == InvalidOffset || SizeInBytes + (Align(m_CurrOffset, size_t{Alignment}) - m_CurrOffset) > m_AvailableSize) { - auto MasterBlock = m_DynamicMemMgr.AllocateMasterBlock(m_MasterBlockSize, 0); + auto MasterBlock = m_GlobalDynamicMemMgr.AllocateMasterBlock(m_MasterBlockSize, 0); if (MasterBlock.UnalignedOffset != InvalidOffset) { m_CurrOffset = MasterBlock.UnalignedOffset; @@ -251,7 +251,7 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A m_PeakUsedSize = std::max(m_PeakUsedSize, m_CurrUsedSize); VERIFY_EXPR((AlignedOffset & (Alignment-1)) == 0); - return VulkanDynamicAllocation{ m_DynamicMemMgr, AlignedOffset, SizeInBytes }; + return VulkanDynamicAllocation{ m_GlobalDynamicMemMgr, AlignedOffset, SizeInBytes }; } else return VulkanDynamicAllocation{}; @@ -259,7 +259,7 @@ VulkanDynamicAllocation VulkanDynamicHeap::Allocate(Uint32 SizeInBytes, Uint32 A void VulkanDynamicHeap::ReleaseMasterBlocks(RenderDeviceVkImpl& DeviceVkImpl, Uint64 CmdQueueMask) { - m_DynamicMemMgr.ReleaseMasterBlocks(m_MasterBlocks, DeviceVkImpl, CmdQueueMask); + m_GlobalDynamicMemMgr.ReleaseMasterBlocks(m_MasterBlocks, DeviceVkImpl, CmdQueueMask); m_MasterBlocks.clear(); m_CurrOffset = InvalidOffset; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp index 4b96f3b7..040a2942 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUploadHeap.cpp @@ -43,17 +43,17 @@ VulkanUploadHeap::~VulkanUploadHeap() LOG_INFO_MESSAGE(m_HeapName, " peak used/peak allocated frame size: ", FormatMemorySize(m_PeakFrameSize, 2, m_PeakAllocatedSize), '/', FormatMemorySize(m_PeakAllocatedSize, 2)); } -VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize SizeInBytes) +VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize SizeInBytes)const { VkBufferCreateInfo StagingBufferCI = {}; - StagingBufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - StagingBufferCI.pNext = nullptr; - StagingBufferCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT - StagingBufferCI.size = SizeInBytes; - StagingBufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - StagingBufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + StagingBufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + StagingBufferCI.pNext = nullptr; + StagingBufferCI.flags = 0; // VK_BUFFER_CREATE_SPARSE_BINDING_BIT, VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, VK_BUFFER_CREATE_SPARSE_ALIASED_BIT + StagingBufferCI.size = SizeInBytes; + StagingBufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + StagingBufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; StagingBufferCI.queueFamilyIndexCount = 0; - StagingBufferCI.pQueueFamilyIndices = nullptr; + StagingBufferCI.pQueueFamilyIndices = nullptr; const auto& LogicalDevice = m_RenderDevice.GetLogicalDevice(); const auto& PhysicalDevice = m_RenderDevice.GetPhysicalDevice(); @@ -62,7 +62,7 @@ VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize Si auto NewBuffer = LogicalDevice.CreateBuffer(StagingBufferCI, "Upload buffer"); auto MemReqs = LogicalDevice.GetBufferMemoryRequirements(NewBuffer); auto MemoryTypeIndex = PhysicalDevice.GetMemoryTypeIndex(MemReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VERIFY(MemoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex, + DEV_CHECK_ERR(MemoryTypeIndex != VulkanUtilities::VulkanPhysicalDevice::InvalidMemoryTypeIndex, "Vulkan spec requires that for a VkBuffer not created with the VK_BUFFER_CREATE_SPARSE_BINDING_BIT " "bit set, or for a VkImage that was created with a VK_IMAGE_TILING_LINEAR value in the tiling member " "of the VkImageCreateInfo structure passed to vkCreateImage, the memoryTypeBits member always contains " @@ -73,7 +73,7 @@ VulkanUploadHeap::UploadPageInfo VulkanUploadHeap::CreateNewPage(VkDeviceSize Si auto AlignedOffset = (MemAllocation.UnalignedOffset + (MemReqs.alignment-1)) & ~(MemReqs.alignment-1); auto err = LogicalDevice.BindBufferMemory(NewBuffer, MemAllocation.Page->GetVkMemory(), AlignedOffset); - CHECK_VK_ERROR_AND_THROW(err, "Failed to bind buffer memory"); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to bind buffer memory"); auto CPUAddress = reinterpret_cast<Uint8*>(MemAllocation.Page->GetCPUMemory()) + AlignedOffset; return UploadPageInfo{std::move(MemAllocation), std::move(NewBuffer), CPUAddress}; diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp index a8dd1d93..9b476773 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanCommandBufferPool.cpp @@ -30,18 +30,18 @@ namespace VulkanUtilities { - VulkanCommandBufferPool::VulkanCommandBufferPool(std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> LogicalDevice, - uint32_t queueFamilyIndex, - VkCommandPoolCreateFlags flags) : - m_LogicalDevice(LogicalDevice) + VulkanCommandBufferPool::VulkanCommandBufferPool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice, + uint32_t queueFamilyIndex, + VkCommandPoolCreateFlags flags) : + m_LogicalDevice(std::move(LogicalDevice)) { VkCommandPoolCreateInfo CmdPoolCI = {}; - CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - CmdPoolCI.pNext = nullptr; + CmdPoolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + CmdPoolCI.pNext = nullptr; CmdPoolCI.queueFamilyIndex = queueFamilyIndex; - CmdPoolCI.flags = flags; + CmdPoolCI.flags = flags; m_CmdPool = m_LogicalDevice->CreateCommandPool(CmdPoolCI); - VERIFY_EXPR(m_CmdPool != VK_NULL_HANDLE); + DEV_CHECK_ERR(m_CmdPool != VK_NULL_HANDLE, "Failed to create vulkan command pool"); } VulkanCommandBufferPool::~VulkanCommandBufferPool() @@ -62,7 +62,7 @@ namespace VulkanUtilities CmdBuffer = m_CmdBuffers.front(); auto err = vkResetCommandBuffer(CmdBuffer, 0 // VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT - specifies that most or all memory resources currently - // owned by the command buffer should be returned to the parent command pool. + // owned by the command buffer should be returned to the parent command pool. ); DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command buffer"); m_CmdBuffers.pop_front(); @@ -73,13 +73,14 @@ namespace VulkanUtilities if (CmdBuffer == VK_NULL_HANDLE) { VkCommandBufferAllocateInfo BuffAllocInfo = {}; - BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - BuffAllocInfo.pNext = nullptr; - BuffAllocInfo.commandPool = m_CmdPool; - BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + BuffAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + BuffAllocInfo.pNext = nullptr; + BuffAllocInfo.commandPool = m_CmdPool; + BuffAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; BuffAllocInfo.commandBufferCount = 1; CmdBuffer = m_LogicalDevice->AllocateVkCommandBuffer(BuffAllocInfo); + DEV_CHECK_ERR(CmdBuffer != VK_NULL_HANDLE, "Failed to allocate vulkan command buffer"); } VkCommandBufferBeginInfo CmdBuffBeginInfo = {}; @@ -100,8 +101,6 @@ namespace VulkanUtilities void VulkanCommandBufferPool::FreeCommandBuffer(VkCommandBuffer&& CmdBuffer) { std::lock_guard<std::mutex> Lock(m_Mutex); - // FenceValue is the value that was signaled by the command queue after it - // executed the command buffer m_CmdBuffers.emplace_back(CmdBuffer); CmdBuffer = VK_NULL_HANDLE; #ifdef DEVELOPMENT diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp index 5293aa21..1467a1db 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanFencePool.cpp @@ -28,7 +28,7 @@ namespace VulkanUtilities { - VulkanFencePool::VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice) : + VulkanFencePool::VulkanFencePool(std::shared_ptr<const VulkanLogicalDevice> LogicalDevice)noexcept : m_LogicalDevice(std::move(LogicalDevice)) {} @@ -36,14 +36,14 @@ namespace VulkanUtilities { for (const auto& fence : m_Fences) { - VERIFY(m_LogicalDevice->GetFenceStatus(fence) == VK_SUCCESS, "Destroying a fence that has not been signaled"); + DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(fence) == VK_SUCCESS, "Destroying a fence that has not been signaled"); } m_Fences.clear(); } - VulkanUtilities::FenceWrapper VulkanFencePool::GetFence() + FenceWrapper VulkanFencePool::GetFence() { - VulkanUtilities::FenceWrapper Fence; + FenceWrapper Fence; if(!m_Fences.empty()) { Fence = std::move(m_Fences.back()); @@ -61,9 +61,9 @@ namespace VulkanUtilities return Fence; } - void VulkanFencePool::DisposeFence(VulkanUtilities::FenceWrapper&& Fence) + void VulkanFencePool::DisposeFence(FenceWrapper&& Fence) { - VERIFY(m_LogicalDevice->GetFenceStatus(Fence) == VK_SUCCESS, "Disposing a fence that has not been signaled"); + DEV_CHECK_ERR(m_LogicalDevice->GetFenceStatus(Fence) == VK_SUCCESS, "Disposing a fence that has not been signaled"); m_Fences.emplace_back(std::move(Fence)); } } |
