diff options
| author | Egor Yusov <egor.yusov@gmail.com> | 2018-09-24 03:30:58 +0000 |
|---|---|---|
| committer | Egor Yusov <egor.yusov@gmail.com> | 2018-09-24 03:30:58 +0000 |
| commit | ef04580d047c3d4e1b34c76c2af8fd6f333af6ff (patch) | |
| tree | 8a71c47ef642952e7886bbec5ba4279e0459e215 /Graphics/GraphicsEngineVulkan | |
| parent | Fixed build - attempt 2 (diff) | |
| download | DiligentCore-ef04580d047c3d4e1b34c76c2af8fd6f333af6ff.tar.gz DiligentCore-ef04580d047c3d4e1b34c76c2af8fd6f333af6ff.zip | |
Reworked dynamic descriptor set allocation/deallocation in Vk backend
Diffstat (limited to 'Graphics/GraphicsEngineVulkan')
16 files changed, 357 insertions, 346 deletions
diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 0a67939f..e7ab3e44 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -37,7 +37,6 @@ set(VULKAN_UTILS_INCLUDE include/VulkanUtilities/VulkanCommandBuffer.h include/VulkanUtilities/VulkanCommandBufferPool.h include/VulkanUtilities/VulkanDebug.h - include/VulkanUtilities/VulkanDescriptorPool.h include/VulkanUtilities/VulkanFencePool.h include/VulkanUtilities/VulkanInstance.h include/VulkanUtilities/VulkanLogicalDevice.h @@ -98,7 +97,6 @@ set(VULKAN_UTILS_SRC src/VulkanUtilities/VulkanCommandBuffer.cpp src/VulkanUtilities/VulkanCommandBufferPool.cpp src/VulkanUtilities/VulkanDebug.cpp - src/VulkanUtilities/VulkanDescriptorPool.cpp src/VulkanUtilities/VulkanFencePool.cpp src/VulkanUtilities/VulkanInstance.cpp src/VulkanUtilities/VulkanLogicalDevice.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h index 6b27d2b4..2f597702 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandPoolManager.h @@ -26,7 +26,7 @@ #include <deque> #include <mutex> #include "STDAllocator.h" -#include "VulkanUtilities/VulkanDescriptorPool.h" +#include "VulkanUtilities/VulkanLogicalDevice.h" namespace Diligent { diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h index 4df8d9f7..0ea4f7eb 100644 --- a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h +++ b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h @@ -29,56 +29,54 @@ #include <vector> #include <deque> #include <mutex> -#include "VulkanUtilities/VulkanDescriptorPool.h" +#include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent { -class DescriptorPoolManager; +class DescriptorSetAllocator; +class RenderDeviceVkImpl; -class DescriptorPoolAllocation +// This class manages descriptor set allocation. +// The class destructor calls DescriptorSetAllocator::FreeDescriptorSet() that moves +// the set into the release queue. +class DescriptorSetAllocation { public: - DescriptorPoolAllocation(VkDescriptorSet _Set, - Uint64 _CmdQueueMask, - VulkanUtilities::VulkanDescriptorPool& _ParentPool, - DescriptorPoolManager& _ParentPoolMgr)noexcept : - Set (_Set), - CmdQueueMask(_CmdQueueMask), - ParentPool (&_ParentPool), - ParentPoolMgr(&_ParentPoolMgr) + DescriptorSetAllocation(VkDescriptorSet _Set, + VkDescriptorPool _Pool, + Uint64 _CmdQueueMask, + DescriptorSetAllocator& _DescrSetAllocator)noexcept : + Set (_Set), + Pool (_Pool), + CmdQueueMask (_CmdQueueMask), + DescrSetAllocator(&_DescrSetAllocator) {} - DescriptorPoolAllocation()noexcept{} + DescriptorSetAllocation()noexcept{} - DescriptorPoolAllocation (const DescriptorPoolAllocation&) = delete; - DescriptorPoolAllocation& operator = (const DescriptorPoolAllocation&) = delete; + DescriptorSetAllocation (const DescriptorSetAllocation&) = delete; + DescriptorSetAllocation& operator = (const DescriptorSetAllocation&) = delete; - DescriptorPoolAllocation(DescriptorPoolAllocation&& rhs)noexcept : - Set (rhs.Set), - CmdQueueMask (rhs.CmdQueueMask), - ParentPool (rhs.ParentPool), - ParentPoolMgr(rhs.ParentPoolMgr) + DescriptorSetAllocation(DescriptorSetAllocation&& rhs)noexcept : + Set (rhs.Set), + CmdQueueMask (rhs.CmdQueueMask), + Pool (rhs.Pool), + DescrSetAllocator(rhs.DescrSetAllocator) { - rhs.Set = VK_NULL_HANDLE; - rhs.CmdQueueMask = 0; - rhs.ParentPool = nullptr; - rhs.ParentPoolMgr = nullptr; + rhs.Reset(); } - DescriptorPoolAllocation& operator = (DescriptorPoolAllocation&& rhs)noexcept + DescriptorSetAllocation& operator = (DescriptorSetAllocation&& rhs)noexcept { Release(); - Set = rhs.Set; - CmdQueueMask = rhs.CmdQueueMask; - ParentPool = rhs.ParentPool; - ParentPoolMgr = rhs.ParentPoolMgr; + Set = rhs.Set; + CmdQueueMask = rhs.CmdQueueMask; + Pool = rhs.Pool; + DescrSetAllocator = rhs.DescrSetAllocator; + + rhs.Reset(); - rhs.Set = VK_NULL_HANDLE; - rhs.CmdQueueMask = 0; - rhs.ParentPool = nullptr; - rhs.ParentPoolMgr = nullptr; - return *this; } @@ -87,9 +85,17 @@ public: return Set != VK_NULL_HANDLE; } + void Reset() + { + Set = VK_NULL_HANDLE; + Pool = VK_NULL_HANDLE; + CmdQueueMask = 0; + DescrSetAllocator = nullptr; + } + void Release(); - ~DescriptorPoolAllocation() + ~DescriptorSetAllocation() { Release(); } @@ -97,66 +103,97 @@ public: VkDescriptorSet GetVkDescriptorSet()const {return Set;} private: - VkDescriptorSet Set = VK_NULL_HANDLE; - Uint64 CmdQueueMask = 0; - VulkanUtilities::VulkanDescriptorPool* ParentPool = nullptr; - DescriptorPoolManager* ParentPoolMgr = nullptr; + VkDescriptorSet Set = VK_NULL_HANDLE; + VkDescriptorPool Pool = VK_NULL_HANDLE; + Uint64 CmdQueueMask = 0; + DescriptorSetAllocator* DescrSetAllocator = nullptr; }; +// The class manages pool of descriptor set pools class DescriptorPoolManager { public: - DescriptorPoolManager(std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> LogicalDevice, - std::vector<VkDescriptorPoolSize> PoolSizes, - uint32_t MaxSets) noexcept: - m_LogicalDevice(std::move(LogicalDevice)), - m_PoolSizes (std::move(PoolSizes)), - m_MaxSets (MaxSets) - { - CreateNewPool(); - } - - // Move constructor must be noexcept, otherwise vector<DescriptorPoolManager> will fail to compile on MSVC - // So we have to implement it manually. = default also does not work - DescriptorPoolManager(DescriptorPoolManager&& rhs)noexcept : - m_PoolSizes (std::move(rhs.m_PoolSizes)), - m_MaxSets (std::move(rhs.m_MaxSets)), - //m_Mutex(std::move(rhs.m_Mutex)), mutex is not movable - m_LogicalDevice (std::move(rhs.m_LogicalDevice)), - m_DescriptorPools (std::move(rhs.m_DescriptorPools)), - m_ReleasedAllocations(std::move(rhs.m_ReleasedAllocations)) + DescriptorPoolManager(RenderDeviceVkImpl& DeviceVkImpl, + std::string PoolName, + std::vector<VkDescriptorPoolSize> PoolSizes, + uint32_t MaxSets, + bool AllowFreeing) noexcept: + m_DeviceVkImpl(DeviceVkImpl), + m_PoolName (std::move(PoolName)), + m_PoolSizes (std::move(PoolSizes)), + m_MaxSets (MaxSets), + m_AllowFreeing(AllowFreeing) { } + ~DescriptorPoolManager(); DescriptorPoolManager (const DescriptorPoolManager&) = delete; DescriptorPoolManager& operator = (const DescriptorPoolManager&) = delete; + DescriptorPoolManager (DescriptorPoolManager&&) = delete; DescriptorPoolManager& operator = (DescriptorPoolManager&&) = delete; + + VulkanUtilities::DescriptorPoolWrapper GetPool(const char* DebugName); + void FreePool(VulkanUtilities::DescriptorPoolWrapper&& Pool); + +protected: + friend class DynamicDescriptorSetAllocator; + VulkanUtilities::DescriptorPoolWrapper CreateDescriptorPool(const char* DebugName); - DescriptorPoolAllocation Allocate(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout); - void DisposeAllocations(uint64_t FenceValue); - void ReleaseStaleAllocations(uint64_t LastCompletedFence); + RenderDeviceVkImpl& m_DeviceVkImpl; + const std::string m_PoolName; + + const std::vector<VkDescriptorPoolSize> m_PoolSizes; + const uint32_t m_MaxSets; + const bool m_AllowFreeing; - size_t GetStaleAllocationCount()const + std::mutex m_Mutex; + std::deque< VulkanUtilities::DescriptorPoolWrapper > m_Pools; +}; + +// The class allocates descriptors from the main descriptor pool. +// Descriptors can be released and returned to the pool +class DescriptorSetAllocator : public DescriptorPoolManager +{ +public: + friend class DescriptorSetAllocation; + DescriptorSetAllocator(RenderDeviceVkImpl& DeviceVkImpl, + std::string PoolName, + std::vector<VkDescriptorPoolSize> PoolSizes, + uint32_t MaxSets, + bool AllowFreeing) noexcept: + DescriptorPoolManager(DeviceVkImpl, std::move(PoolName), std::move(PoolSizes), MaxSets, AllowFreeing) { - return m_ReleasedAllocations.size(); } - size_t GetPendingReleaseAllocationCount(); -private: - friend class DescriptorPoolAllocation; - void FreeAllocation(VkDescriptorSet Set, VulkanUtilities::VulkanDescriptorPool& Pool); + DescriptorSetAllocation Allocate(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout); - void CreateNewPool(); +private: + void FreeDescriptorSet(VkDescriptorSet Set, VkDescriptorPool Pool, Uint64 QueueMask); +}; - const std::vector<VkDescriptorPoolSize> m_PoolSizes; - const uint32_t m_MaxSets; +// The class manages dynamic descriptor sets. It first requests descriptor pool from +// the global manager and performs allocations from this pool. When space in the pool is exhausted, +// the class requests new pool. +// The class is not thread-safe as device contexts must not be used in multiple threads at the same time. +// Entire pools are recycled at the end of every frame. +class DynamicDescriptorSetAllocator +{ +public: + DynamicDescriptorSetAllocator(DescriptorPoolManager& PoolMgr, std::string Name) : + m_PoolMgr(PoolMgr), + m_Name(std::move(Name)) + {} + ~DynamicDescriptorSetAllocator(); - std::mutex m_Mutex; - std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> m_LogicalDevice; - std::deque< std::unique_ptr<VulkanUtilities::VulkanDescriptorPool> > m_DescriptorPools; - std::vector< std::pair<VkDescriptorSet, VulkanUtilities::VulkanDescriptorPool*> > m_ReleasedAllocations; + VkDescriptorSet Allocate(VkDescriptorSetLayout SetLayout, const char* DebugName); + void ReleasePools(Uint64 QueueMask); + size_t GetAllocatedPoolCount()const{return m_AllocatedPools.size();} - // When adding new members, do not forget to update move ctor! +private: + DescriptorPoolManager& m_PoolMgr; + 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 1c701a7d..ae443b34 100644 --- a/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/DeviceContextVkImpl.h @@ -166,11 +166,11 @@ public: virtual void FinishFrame(bool ForceRelease)override final; void FinishFrame(Uint64 CompletedFenceValue); - DescriptorPoolAllocation AllocateDynamicDescriptorSet(VkDescriptorSetLayout SetLayout) + VkDescriptorSet AllocateDynamicDescriptorSet(VkDescriptorSetLayout 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 m_DynamicDescriptorPool.Allocate( Uint64{1} << Uint64{m_CommandQueueId}, SetLayout); + return m_DynamicDescrSetAllocator.Allocate(SetLayout, ""); } VulkanDynamicAllocation AllocateDynamicSpace(Uint32 SizeInBytes, Uint32 Alignment); @@ -291,8 +291,8 @@ private: - VulkanUploadHeap m_UploadHeap; - DescriptorPoolManager m_DynamicDescriptorPool; + VulkanUploadHeap m_UploadHeap; + DynamicDescriptorSetAllocator m_DynamicDescrSetAllocator; // Number of the command buffer currently being recorded by the context and that will // be submitted next diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h index a1072089..d326e0f6 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h @@ -101,10 +101,11 @@ public: void FinishFrame(bool ReleaseAllResources); virtual void FinishFrame()override final { FinishFrame(false); } - DescriptorPoolAllocation AllocateDescriptorSet(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout) + DescriptorSetAllocation AllocateDescriptorSet(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout) { - return m_MainDescriptorPool.Allocate(CommandQueueMask, SetLayout); + return m_DescriptorSetAllocator.Allocate(CommandQueueMask, SetLayout); } + DescriptorPoolManager& GetDynamicDescriptorPool(){return m_DynamicDescriptorPool;} std::shared_ptr<const VulkanUtilities::VulkanInstance> GetVulkanInstance()const{return m_VulkanInstance;} const VulkanUtilities::VulkanPhysicalDevice& GetPhysicalDevice()const {return *m_PhysicalDevice;} @@ -137,9 +138,10 @@ private: EngineVkAttribs m_EngineAttribs; - FramebufferCache m_FramebufferCache; - RenderPassCache m_RenderPassCache; - DescriptorPoolManager m_MainDescriptorPool; + FramebufferCache m_FramebufferCache; + RenderPassCache m_RenderPassCache; + DescriptorSetAllocator m_DescriptorSetAllocator; + DescriptorPoolManager m_DynamicDescriptorPool; // These one-time command pools are used by buffer and texture constructors to // issue copy commands. Vulkan requires that every command pool is used by one thread diff --git a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h index 1531d851..36d58469 100644 --- a/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h +++ b/Graphics/GraphicsEngineVulkan/include/ShaderResourceCacheVk.h @@ -140,7 +140,7 @@ public: return m_DescriptorSetAllocation.GetVkDescriptorSet(); } - void AssignDescriptorSetAllocation(DescriptorPoolAllocation&& Allocation) + void AssignDescriptorSetAllocation(DescriptorSetAllocation&& Allocation) { VERIFY(m_NumResources > 0, "Descriptor set is empty"); m_DescriptorSetAllocation = std::move(Allocation); @@ -150,7 +150,7 @@ public: private: Resource* const m_pResources = nullptr; - DescriptorPoolAllocation m_DescriptorSetAllocation; + DescriptorSetAllocation m_DescriptorSetAllocation; }; inline DescriptorSet& GetDescriptorSet(Uint32 Index) diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h deleted file mode 100644 index 7a429147..00000000 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. -* -* In no event and under no legal theory, whether in tort (including negligence), -* contract, or otherwise, unless required by applicable law (such as deliberate -* and grossly negligent acts) or agreed to in writing, shall any Contributor be -* liable for any damages, including any direct, indirect, special, incidental, -* or consequential damages of any character arising as a result of this License or -* out of the use or inability to use the software (including but not limited to damages -* for loss of goodwill, work stoppage, computer failure or malfunction, or any and -* all other commercial damages or losses), even if such Contributor has been advised -* of the possibility of such damages. -*/ - -#pragma once - -#include <deque> -#include <memory> -#include "vulkan.h" -#include "VulkanLogicalDevice.h" -#include "VulkanObjectWrappers.h" - -namespace VulkanUtilities -{ - class VulkanDescriptorPool - { - public: - VulkanDescriptorPool(std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> LogicalDevice, - const VkDescriptorPoolCreateInfo& DescriptorPoolCI); - - VulkanDescriptorPool (const VulkanDescriptorPool&) = delete; - VulkanDescriptorPool& operator = (const VulkanDescriptorPool&) = delete; - VulkanDescriptorPool (VulkanDescriptorPool&&) = default; - VulkanDescriptorPool& operator = (VulkanDescriptorPool&&) = default; - ~VulkanDescriptorPool(); - - VkDescriptorSet AllocateDescriptorSet(VkDescriptorSetLayout SetLayout, const char* DebugName = ""); - void DisposeDescriptorSet(VkDescriptorSet DescrSet, uint64_t FenceValue); - void ReleaseDiscardedSets(uint64_t LastCompletedFence); - - DescriptorPoolWrapper&& Release(); - - size_t GetDiscardedSetCount()const - { - return m_DiscardedSets.size(); - } - - private: - // Shared point to logical device must be defined before the command pool - std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> m_LogicalDevice; - DescriptorPoolWrapper m_Pool; - - // fist - the fence value associated with the command buffer referencing the set - // when it was executed - // second - the descriptor set - typedef std::pair<uint64_t, VkDescriptorSet > QueueElemType; - std::deque< QueueElemType > m_DiscardedSets; - }; -} diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h index 6fd7e33c..a9cf747d 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanLogicalDevice.h @@ -123,6 +123,9 @@ namespace VulkanUtilities VkResult ResetCommandPool(VkCommandPool vkCmdPool, VkCommandPoolResetFlags flags = 0)const; + VkResult ResetDescriptorPool(VkDescriptorPool descriptorPool, + VkDescriptorPoolResetFlags flags = 0)const; + private: VulkanLogicalDevice(VkPhysicalDevice vkPhysicalDevice, const VkDeviceCreateInfo &DeviceCI, diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp index fe6e9c9f..f05894e8 100644 --- a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp @@ -28,20 +28,18 @@ namespace Diligent { -void DescriptorPoolAllocation::Release() +void DescriptorSetAllocation::Release() { if (Set != VK_NULL_HANDLE) { - VERIFY_EXPR(ParentPoolMgr != nullptr && ParentPool != nullptr); - ParentPoolMgr->FreeAllocation(Set, *ParentPool); + VERIFY_EXPR(DescrSetAllocator != nullptr && Pool != nullptr); + DescrSetAllocator->FreeDescriptorSet(Set, Pool, CmdQueueMask); - Set = VK_NULL_HANDLE; - ParentPoolMgr = nullptr; - ParentPool = nullptr; + Reset(); } } -void DescriptorPoolManager::CreateNewPool() +VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::CreateDescriptorPool(const char* DebugName) { VkDescriptorPoolCreateInfo PoolCI = {}; PoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -49,77 +47,201 @@ void DescriptorPoolManager::CreateNewPool() // 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 = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + 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(); - m_DescriptorPools.emplace_front( new VulkanUtilities::VulkanDescriptorPool(m_LogicalDevice, PoolCI) ); + return m_DeviceVkImpl.GetLogicalDevice().CreateDescriptorPool(PoolCI, DebugName); } -DescriptorPoolAllocation DescriptorPoolManager::Allocate(Uint64 CommandQueueMask, VkDescriptorSetLayout SetLayout) +DescriptorPoolManager::~DescriptorPoolManager() +{ + LOG_INFO_MESSAGE(m_PoolName, " stats: allocated ", m_Pools.size(), " pool(s)"); +} + +VulkanUtilities::DescriptorPoolWrapper DescriptorPoolManager::GetPool(const char* DebugName) +{ + std::lock_guard<std::mutex> Lock(m_Mutex); + if (m_Pools.empty()) + return CreateDescriptorPool(DebugName); + else + { + auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); + auto Pool = std::move(m_Pools.front()); + VulkanUtilities::SetDescriptorPoolName(LogicalDevice.GetVkDevice(), Pool, DebugName); + m_Pools.pop_front(); + return Pool; + } +} + +void DescriptorPoolManager::FreePool(VulkanUtilities::DescriptorPoolWrapper&& Pool) +{ + std::lock_guard<std::mutex> Lock(m_Mutex); + m_DeviceVkImpl.GetLogicalDevice().ResetDescriptorPool(Pool); + m_Pools.emplace_back(std::move(Pool)); +} + + +static VkDescriptorSet AllocateDescriptorSet(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice, + VkDescriptorPool Pool, + VkDescriptorSetLayout SetLayout, + const char* DebugName) +{ + VkDescriptorSetAllocateInfo DescrSetAllocInfo = {}; + DescrSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + DescrSetAllocInfo.pNext = nullptr; + DescrSetAllocInfo.descriptorPool = Pool; + DescrSetAllocInfo.descriptorSetCount = 1; + 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); +} + + +DescriptorSetAllocation DescriptorSetAllocator::Allocate(Uint64 CommandQueueMask, VkDescriptorSetLayout 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) std::lock_guard<std::mutex> Lock(m_Mutex); + const auto& LogicalDevice = m_DeviceVkImpl.GetLogicalDevice(); // Try all pools starting from the frontmost - for(auto it = m_DescriptorPools.begin(); it != m_DescriptorPools.end(); ++it) + for(auto it = m_Pools.begin(); it != m_Pools.end(); ++it) { - auto& Pool = *(*it); - auto Set = Pool.AllocateDescriptorSet(SetLayout); - if(Set != VK_NULL_HANDLE) + auto& Pool = *it; + auto Set = AllocateDescriptorSet(LogicalDevice, Pool, SetLayout, "Descriptor set"); + if (Set != VK_NULL_HANDLE) { // Move the pool to the front - if(it != m_DescriptorPools.begin()) + if (it != m_Pools.begin()) { - std::swap(*it, m_DescriptorPools.front()); + std::swap(*it, m_Pools.front()); } - return {Set, CommandQueueMask, Pool, *this}; + return {Set, Pool, CommandQueueMask, *this}; } } // Failed to allocate descriptor from existing pools -> create a new one - CreateNewPool(); LOG_INFO_MESSAGE("Allocated new descriptor pool"); + m_Pools.emplace_front(CreateDescriptorPool("Descriptor pool")); - auto &NewPool = *m_DescriptorPools.front(); - auto Set = NewPool.AllocateDescriptorSet(SetLayout); + auto& NewPool = m_Pools.front(); + auto Set = AllocateDescriptorSet(LogicalDevice, NewPool, SetLayout, ""); VERIFY(Set != VK_NULL_HANDLE, "Failed to allocate descriptor set"); - return {Set, CommandQueueMask, NewPool, *this }; + return {Set, NewPool, CommandQueueMask, *this }; } -void DescriptorPoolManager::FreeAllocation(VkDescriptorSet Set, VulkanUtilities::VulkanDescriptorPool& Pool) +void DescriptorSetAllocator::FreeDescriptorSet(VkDescriptorSet Set, VkDescriptorPool Pool, Uint64 QueueMask) { - std::lock_guard<std::mutex> Lock(m_Mutex); - m_ReleasedAllocations.emplace_back(std::make_pair(Set, &Pool)); + class DescriptorSetDeleter + { + public: + DescriptorSetDeleter(DescriptorSetAllocator& _Allocator, + VkDescriptorSet _Set, + VkDescriptorPool _Pool) : + Allocator (&_Allocator), + Set (_Set), + Pool (_Pool) + {} + + DescriptorSetDeleter (const DescriptorSetDeleter&) = delete; + DescriptorSetDeleter& operator = (const DescriptorSetDeleter&) = delete; + DescriptorSetDeleter& operator = ( DescriptorSetDeleter&&)= delete; + + DescriptorSetDeleter(DescriptorSetDeleter&& rhs)noexcept : + Allocator (rhs.Allocator), + Set (rhs.Set), + Pool (rhs.Pool) + { + rhs.Allocator = nullptr; + rhs.Set = nullptr; + rhs.Pool = nullptr; + } + + ~DescriptorSetDeleter() + { + if (Allocator!=nullptr) + { + std::lock_guard<std::mutex> Lock(Allocator->m_Mutex); + Allocator->m_DeviceVkImpl.GetLogicalDevice().FreeDescriptorSet(Pool, Set); + } + } + + private: + DescriptorSetAllocator* Allocator; + VkDescriptorSet Set; + VkDescriptorPool Pool; + }; + m_DeviceVkImpl.SafeReleaseDeviceObject(DescriptorSetDeleter{*this, Set, Pool}, QueueMask); } -void DescriptorPoolManager::DisposeAllocations(uint64_t FenceValue) + +VkDescriptorSet DynamicDescriptorSetAllocator::Allocate(VkDescriptorSetLayout SetLayout, const char* DebugName) { - std::lock_guard<std::mutex> Lock(m_Mutex); - for(auto &Allocation : m_ReleasedAllocations) + VkDescriptorSet set = VK_NULL_HANDLE; + const auto& LogicalDevice = m_PoolMgr.m_DeviceVkImpl.GetLogicalDevice(); + if (!m_AllocatedPools.empty()) { - Allocation.second->DisposeDescriptorSet(Allocation.first, FenceValue); + set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); } - m_ReleasedAllocations.clear(); + + if (set == VK_NULL_HANDLE) + { + m_AllocatedPools.emplace_back(m_PoolMgr.GetPool("Dynamic Descriptor Pool")); + set = AllocateDescriptorSet(LogicalDevice, m_AllocatedPools.back(), SetLayout, DebugName); + } + + return set; } -void DescriptorPoolManager::ReleaseStaleAllocations(uint64_t LastCompletedFence) +void DynamicDescriptorSetAllocator::ReleasePools(Uint64 QueueMask) { - std::lock_guard<std::mutex> Lock(m_Mutex); - for(auto &Pool : m_DescriptorPools) - Pool->ReleaseDiscardedSets(LastCompletedFence); + class DescriptorPoolDeleter + { + public: + DescriptorPoolDeleter(DescriptorPoolManager& _PoolMgr, + VulkanUtilities::DescriptorPoolWrapper&& _Pool) : + 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_PeakPoolCount = std::max(m_PeakPoolCount, m_AllocatedPools.size()); + m_AllocatedPools.clear(); } -size_t DescriptorPoolManager::GetPendingReleaseAllocationCount() +DynamicDescriptorSetAllocator::~DynamicDescriptorSetAllocator() { - size_t count = 0; - std::lock_guard<std::mutex> Lock(m_Mutex); - for(auto &Pool : m_DescriptorPools) - count += Pool->GetDiscardedSetCount(); - return count; + LOG_INFO_MESSAGE(m_Name, " peak descriptor pool count: ", m_PeakPoolCount); } - } diff --git a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp index 8c6e0b56..c067f768 100644 --- a/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/DeviceContextVkImpl.cpp @@ -34,28 +34,15 @@ namespace Diligent { - static std::string GetUploadHeapName(bool bIsDeferred, Uint32 ContextId) - { - if (bIsDeferred) - { - std::stringstream ss; - ss << "Upload heap of deferred context #" << ContextId; - return ss.str(); - } - else - return "Upload heap of immediate context"; - } - - static std::string GetDynamicHeapName(bool bIsDeferred, Uint32 ContextId) + static std::string GetContextObjectName(const char* Object, bool bIsDeferred, Uint32 ContextId) { + std::stringstream ss; + ss << Object; if (bIsDeferred) - { - std::stringstream ss; - ss << "Dynamic heap of deferred context #" << ContextId; - return ss.str(); - } + ss << " of deferred context #" << ContextId; else - return "Dynamic heap of immediate context"; + ss << " of immediate context"; + return ss.str(); } DeviceContextVkImpl::DeviceContextVkImpl( IReferenceCounters* pRefCounters, @@ -83,36 +70,22 @@ namespace Diligent m_UploadHeap { *pDeviceVkImpl, - GetUploadHeapName(bIsDeferred, ContextId), + GetContextObjectName("Upload heap", bIsDeferred, ContextId), Attribs.UploadHeapPageSize }, - // Descriptor pools must always be thread-safe as for a deferred context, Finish() may be called from another thread - m_DynamicDescriptorPool - { - pDeviceVkImpl->GetLogicalDevice().GetSharedPtr(), - std::vector<VkDescriptorPoolSize> - { - {VK_DESCRIPTOR_TYPE_SAMPLER, Attribs.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, Attribs.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors}, - {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, Attribs.DynamicDescriptorPoolSize.NumSampledImageDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, Attribs.DynamicDescriptorPoolSize.NumStorageImageDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, Attribs.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, Attribs.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, Attribs.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, - //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, Attribs.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, Attribs.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, - {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, Attribs.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, - }, - Attribs.DynamicDescriptorPoolSize.MaxDescriptorSets, - }, m_NextCmdBuffNumber(0), m_ContextFrameNumber(0), m_DynamicHeap { pDeviceVkImpl->GetDynamicMemoryManager(), - GetDynamicHeapName(bIsDeferred, ContextId), + GetContextObjectName("Dynamic heap", bIsDeferred, ContextId), Attribs.DynamicHeapPageSize }, + m_DynamicDescrSetAllocator + { + pDeviceVkImpl->GetDynamicDescriptorPool(), + GetContextObjectName("Dynamic descriptor set allocator", bIsDeferred, ContextId), + }, m_GenerateMipsHelper(std::move(GenerateMipsHelper)) { m_GenerateMipsHelper->CreateSRB(&m_GenerateMipsSRB); @@ -153,11 +126,13 @@ namespace Diligent // moved to the release queue by Flush(). For deferred contexts, this should have happened in the last FinishCommandList() // call. VERIFY(m_UploadHeap.GetStalePagesCount() == 0, "All stale pages must have been discarded at this point"); - VERIFY(m_DynamicDescriptorPool.GetStaleAllocationCount() == 0, "All stale dynamic descriptor set allocations must have been discarded at this point"); + VERIFY(m_DynamicDescrSetAllocator.GetAllocatedPoolCount() == 0, "All allocated dynamic descriptor set pools must have been released at this point"); + // TODO: rework ReleaseStaleContextResources(m_LastSubmittedFenceValue, pDeviceVkImpl->GetCompletedFenceValue(0)); // Since we idled the GPU, all stale resources must have been destroyed now - VERIFY(m_DynamicDescriptorPool.GetPendingReleaseAllocationCount() == 0, "All stale descriptor set allocations must have been destroyed at this point"); + // TODO: remove + //VERIFY(m_DynamicDescriptorPool.GetPendingReleaseAllocationCount() == 0, "All stale descriptor set allocations must have been destroyed at this point"); auto VkCmdPool = m_CmdPool.Release(); pDeviceVkImpl->SafeReleaseDeviceObject(std::move(VkCmdPool), ~Uint64{0}); @@ -762,8 +737,7 @@ namespace Diligent // the release queue rightaway when RenderDeviceVkImpl::FlushStaleResources() is called m_UploadHeap.ReleaseAllocatedPages(m_SubmittedBuffersCmdQueueMask); m_DynamicHeap.FinishFrame(DeviceVkImpl, m_SubmittedBuffersCmdQueueMask); - - m_DynamicDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); + m_DynamicDescrSetAllocator.ReleasePools(m_SubmittedBuffersCmdQueueMask); if (m_bIsDeferred) { @@ -781,8 +755,8 @@ namespace Diligent void DeviceContextVkImpl::ReleaseStaleContextResources(Uint64 SubmittedFenceValue, Uint64 CompletedFenceValue) { - m_DynamicDescriptorPool.DisposeAllocations(SubmittedFenceValue); - m_DynamicDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); + //m_DynamicDescriptorPool.DisposeAllocations(SubmittedFenceValue); + //m_DynamicDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); } void DeviceContextVkImpl::Flush() diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp index cd5c0c65..dc1085a4 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineLayout.cpp @@ -416,7 +416,7 @@ void PipelineLayout::InitResourceCache(RenderDeviceVkImpl* pDeviceVkImpl, Shader const auto &StaticAndMutSet = m_LayoutMgr.GetDescriptorSet(SHADER_VARIABLE_TYPE_STATIC); if (StaticAndMutSet.SetIndex >= 0) { - DescriptorPoolAllocation SetAllocation = pDeviceVkImpl->AllocateDescriptorSet(~Uint64{0}, StaticAndMutSet.VkLayout); + DescriptorSetAllocation SetAllocation = pDeviceVkImpl->AllocateDescriptorSet(~Uint64{0}, StaticAndMutSet.VkLayout); ResourceCache.GetDescriptorSet(StaticAndMutSet.SetIndex).AssignDescriptorSetAllocation(std::move(SetAllocation)); } } diff --git a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp index d41983f0..3161d084 100644 --- a/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp @@ -551,23 +551,23 @@ void PipelineStateVkImpl::CommitAndTransitionShaderResources(IShaderResourceBind #endif } - DescriptorPoolAllocation DynamicDescrSetAllocation; + VkDescriptorSet DynamicDescrSet = VK_NULL_HANDLE; auto DynamicDescriptorSetVkLayout = m_PipelineLayout.GetDynamicDescriptorSetVkLayout(); if (DynamicDescriptorSetVkLayout != VK_NULL_HANDLE) { // Allocate vulkan descriptor set for dynamic resources - DynamicDescrSetAllocation = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout); + DynamicDescrSet = pCtxVkImpl->AllocateDynamicDescriptorSet(DynamicDescriptorSetVkLayout); // Commit all dynamic resource descriptors for (Uint32 s=0; s < m_NumShaders; ++s) { const auto& Layout = m_ShaderResourceLayouts[s]; if (Layout.GetResourceCount(SHADER_VARIABLE_TYPE_DYNAMIC) != 0) - Layout.CommitDynamicResources(ResourceCache, DynamicDescrSetAllocation.GetVkDescriptorSet()); + Layout.CommitDynamicResources(ResourceCache, DynamicDescrSet); } } // Prepare descriptor sets, and also bind them if there are no dynamic descriptors VERIFY_EXPR(pDescrSetBindInfo != nullptr); - m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline, ResourceCache, *pDescrSetBindInfo, DynamicDescrSetAllocation.GetVkDescriptorSet()); + m_PipelineLayout.PrepareDescriptorSets(pCtxVkImpl, m_Desc.IsComputePipeline, ResourceCache, *pDescrSetBindInfo, DynamicDescrSet); // Dynamic descriptor set allocation automatically goes back to the context's dynamic descriptor pool. // release queue. It will stay there until the next command list is executed, at which point it will be discarded // and actually released later diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index f0c8a29e..67729dfc 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -70,9 +70,10 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters* m_EngineAttribs(CreationAttribs), m_FramebufferCache(*this), m_RenderPassCache(*this), - m_MainDescriptorPool + m_DescriptorSetAllocator { - m_LogicalVkDevice, + *this, + "Main descriptor pool", std::vector<VkDescriptorPoolSize> { {VK_DESCRIPTOR_TYPE_SAMPLER, CreationAttribs.MainDescriptorPoolSize.NumSeparateSamplerDescriptors}, @@ -86,7 +87,28 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters* {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, CreationAttribs.MainDescriptorPoolSize.NumUniformBufferDescriptors}, {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, CreationAttribs.MainDescriptorPoolSize.NumStorageBufferDescriptors}, }, - CreationAttribs.MainDescriptorPoolSize.MaxDescriptorSets + CreationAttribs.MainDescriptorPoolSize.MaxDescriptorSets, + true + }, + m_DynamicDescriptorPool + { + *this, + "Dynamic descriptor pool", + std::vector<VkDescriptorPoolSize> + { + {VK_DESCRIPTOR_TYPE_SAMPLER, CreationAttribs.DynamicDescriptorPoolSize.NumSeparateSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, CreationAttribs.DynamicDescriptorPoolSize.NumCombinedSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, CreationAttribs.DynamicDescriptorPoolSize.NumSampledImageDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, CreationAttribs.DynamicDescriptorPoolSize.NumStorageImageDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, CreationAttribs.DynamicDescriptorPoolSize.NumUniformTexelBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, CreationAttribs.DynamicDescriptorPoolSize.NumStorageTexelBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, CreationAttribs.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, + //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, CreationAttribs.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, CreationAttribs.DynamicDescriptorPoolSize.NumUniformBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, CreationAttribs.DynamicDescriptorPoolSize.NumStorageBufferDescriptors}, + }, + CreationAttribs.DynamicDescriptorPoolSize.MaxDescriptorSets, + false // Pools can only be reset }, m_TransientCmdPoolMgr(*m_LogicalVkDevice, CmdQueues[0]->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT), m_MemoryMgr("Global resource memory manager", *m_LogicalVkDevice, *m_PhysicalDevice, GetRawAllocator(), CreationAttribs.DeviceLocalMemoryPageSize, CreationAttribs.HostVisibleMemoryPageSize, CreationAttribs.DeviceLocalMemoryReserveSize, CreationAttribs.HostVisibleMemoryReserveSize), @@ -243,8 +265,8 @@ Uint64 RenderDeviceVkImpl::ExecuteCommandBuffer(const VkSubmitInfo& SubmitInfo, SubmitCommandBuffer(SubmitInfo, SubmittedCmdBuffNumber, SubmittedFenceValue, pSignalFences); // TODO: rework this - auto CompletedFenceValue = m_CommandQueues[0].CmdQueue->GetCompletedFenceValue(); - m_MainDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); + //auto CompletedFenceValue = m_CommandQueues[0].CmdQueue->GetCompletedFenceValue(); + //m_MainDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); m_MemoryMgr.ShrinkMemory(); PurgeReleaseQueues(); @@ -265,7 +287,7 @@ void RenderDeviceVkImpl::IdleGPU(bool ReleaseStaleObjects) // Since GPU has been idled, it it is safe to do so // SubmittedFenceValue has now been signaled by the GPU since we waited for it - m_MainDescriptorPool.ReleaseStaleAllocations(m_CommandQueues[0].CmdQueue->GetCompletedFenceValue()); + //m_MainDescriptorPool.ReleaseStaleAllocations(m_CommandQueues[0].CmdQueue->GetCompletedFenceValue()); m_MemoryMgr.ShrinkMemory(); } } @@ -291,7 +313,7 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) // TODO: rework this auto CompletedFenceValue = ReleaseAllResources ? std::numeric_limits<Uint64>::max() : m_CommandQueues[0].CmdQueue->GetCompletedFenceValue(); - m_MainDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); + //m_MainDescriptorPool.ReleaseStaleAllocations(CompletedFenceValue); m_MemoryMgr.ShrinkMemory(); PurgeReleaseQueues(); diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp deleted file mode 100644 index 9113023e..00000000 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2015-2018 Egor Yusov -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. -* -* In no event and under no legal theory, whether in tort (including negligence), -* contract, or otherwise, unless required by applicable law (such as deliberate -* and grossly negligent acts) or agreed to in writing, shall any Contributor be -* liable for any damages, including any direct, indirect, special, incidental, -* or consequential damages of any character arising as a result of this License or -* out of the use or inability to use the software (including but not limited to damages -* for loss of goodwill, work stoppage, computer failure or malfunction, or any and -* all other commercial damages or losses), even if such Contributor has been advised -* of the possibility of such damages. -*/ -#include <sstream> - -#include "VulkanUtilities/VulkanDescriptorPool.h" -#include "VulkanUtilities/VulkanDebug.h" -#include "Errors.h" -#include "DebugUtilities.h" -#include "VulkanErrors.h" - -namespace VulkanUtilities -{ - VulkanDescriptorPool::VulkanDescriptorPool(std::shared_ptr<const VulkanUtilities::VulkanLogicalDevice> LogicalDevice, - const VkDescriptorPoolCreateInfo& DescriptorPoolCI) : - m_LogicalDevice(LogicalDevice) - { - VERIFY_EXPR(DescriptorPoolCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO); - m_Pool = m_LogicalDevice->CreateDescriptorPool(DescriptorPoolCI); - VERIFY_EXPR(m_Pool != VK_NULL_HANDLE); - } - - VulkanDescriptorPool::~VulkanDescriptorPool() - { - m_Pool.Release(); - } - - VkDescriptorSet VulkanDescriptorPool::AllocateDescriptorSet(VkDescriptorSetLayout SetLayout, const char* DebugName) - { - VkDescriptorSetAllocateInfo DescrSetAllocInfo = {}; - DescrSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - DescrSetAllocInfo.pNext = nullptr; - DescrSetAllocInfo.descriptorPool = m_Pool; - DescrSetAllocInfo.descriptorSetCount = 1; - 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 m_LogicalDevice->AllocateVkDescriptorSet(DescrSetAllocInfo, DebugName); - } - - void VulkanDescriptorPool::ReleaseDiscardedSets(uint64_t LastCompletedFence) - { - // Pick the oldest descriptor set at the front of the deque. - // .first is the fence value that was signaled AFTER the command buffer referencing - // the set has been submitted. If LastCompletedFence is at least this value, the buffer - // is now finished, and the set can be safely released - while (!m_DiscardedSets.empty() && LastCompletedFence >= m_DiscardedSets.front().first ) - { - m_LogicalDevice->FreeDescriptorSet(m_Pool, m_DiscardedSets.front().second); - m_DiscardedSets.pop_front(); - } - } - - void VulkanDescriptorPool::DisposeDescriptorSet(VkDescriptorSet DescrSet, uint64_t FenceValue) - { - // FenceValue is the value that was signaled by the command queue after it - // executed the command buffer - m_DiscardedSets.emplace_back(FenceValue, DescrSet); - } - - DescriptorPoolWrapper&& VulkanDescriptorPool::Release() - { - m_LogicalDevice.reset(); - VERIFY(m_DiscardedSets.empty(), "Discarded sets are not released"); - m_DiscardedSets.clear(); - return std::move(m_Pool); - } -} diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp index 71329665..490151c5 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanLogicalDevice.cpp @@ -71,7 +71,7 @@ namespace VulkanUtilities void VulkanLogicalDevice::WaitIdle()const { auto err = vkDeviceWaitIdle(m_VkDevice); - VERIFY_EXPR(err == VK_SUCCESS); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to idle device"); } template<typename VkObjectType, typename VkCreateObjectFuncType, typename VkObjectCreateInfoType> @@ -248,7 +248,7 @@ namespace VulkanUtilities VkCommandBuffer CmdBuff = VK_NULL_HANDLE; auto err = vkAllocateCommandBuffers(m_VkDevice, &AllocInfo, &CmdBuff); - VERIFY(err == VK_SUCCESS, "Failed to allocate command buffer '", DebugName, '\''); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to allocate command buffer '", DebugName, '\''); if (DebugName != nullptr && *DebugName != 0) SetCommandBufferName(m_VkDevice, CmdBuff, DebugName); @@ -423,7 +423,7 @@ namespace VulkanUtilities VkResult VulkanLogicalDevice::ResetFence(VkFence fence)const { auto err = vkResetFences(m_VkDevice, 1, &fence); - VERIFY(err == VK_SUCCESS, "Failed to reset fence"); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset fence"); return err; } @@ -439,7 +439,15 @@ namespace VulkanUtilities VkCommandPoolResetFlags flags)const { auto err = vkResetCommandPool(m_VkDevice, vkCmdPool, flags); - VERIFY(err == VK_SUCCESS, "Failed to reset command pool"); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset command pool"); + return err; + } + + VkResult VulkanLogicalDevice::ResetDescriptorPool(VkDescriptorPool vkDescriptorPool, + VkDescriptorPoolResetFlags flags)const + { + auto err = vkResetDescriptorPool(m_VkDevice, vkDescriptorPool, flags); + DEV_CHECK_ERR(err == VK_SUCCESS, "Failed to reset descriptor pool"); return err; } } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp index b5dcee74..cad556aa 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanPhysicalDevice.cpp @@ -151,7 +151,7 @@ namespace VulkanUtilities // VkPhysicalDeviceMemoryProperties structure for the physical device is // supported for the resource. // * requiredProperties - required memory properties (device local, host visible, etc.) - uint32_t VulkanPhysicalDevice::GetMemoryTypeIndex(uint32_t memoryTypeBitsRequirement, + uint32_t VulkanPhysicalDevice::GetMemoryTypeIndex(uint32_t memoryTypeBitsRequirement, VkMemoryPropertyFlags requiredProperties)const { // Iterate over all memory types available for the device |
