From 8f10dad3656381cfa663f3cef71561bf2265164a Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Fri, 11 May 2018 20:51:38 -0700 Subject: Added descriptor pool manager --- Graphics/GraphicsEngineVulkan/CMakeLists.txt | 4 +- .../include/BufferViewVkImpl.h | 1 - .../GraphicsEngineVulkan/include/CommandContext.h | 9 +- .../GraphicsEngineVulkan/include/DescriptorHeap.h | 532 --------------------- .../include/DescriptorPoolManager.h | 119 +++++ .../include/RenderDeviceVkImpl.h | 18 +- .../include/VulkanUtilities/VulkanDescriptorPool.h | 8 +- .../GraphicsEngineVulkan/src/CommandContext.cpp | 2 + .../GraphicsEngineVulkan/src/DescriptorHeap.cpp | 428 ----------------- .../src/DescriptorPoolManager.cpp | 110 +++++ .../src/RenderDeviceVkImpl.cpp | 102 ++-- .../src/VulkanUtilities/VulkanDescriptorPool.cpp | 2 +- 12 files changed, 317 insertions(+), 1018 deletions(-) delete mode 100644 Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h create mode 100644 Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h delete mode 100644 Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp create mode 100644 Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp (limited to 'Graphics/GraphicsEngineVulkan') diff --git a/Graphics/GraphicsEngineVulkan/CMakeLists.txt b/Graphics/GraphicsEngineVulkan/CMakeLists.txt index 7d489fc1..259fc8bd 100644 --- a/Graphics/GraphicsEngineVulkan/CMakeLists.txt +++ b/Graphics/GraphicsEngineVulkan/CMakeLists.txt @@ -10,7 +10,7 @@ set(INCLUDE include/CommandQueueVkImpl.h include/VulkanResourceBase.h include/VulkanTypeConversions.h - include/DescriptorHeap.h + include/DescriptorPoolManager.h include/DeviceContextVkImpl.h include/DynamicUploadHeap.h include/FramebufferCache.h @@ -67,7 +67,7 @@ set(SRC src/CommandQueueVkImpl.cpp src/VulkanResourceBase.cpp src/VulkanTypeConversions.cpp - src/DescriptorHeap.cpp + src/DescriptorPoolManager.cpp src/DeviceContextVkImpl.cpp src/DynamicUploadHeap.cpp src/FramebufferCache.cpp diff --git a/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h index 71506640..1cfe3ac0 100644 --- a/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/BufferViewVkImpl.h @@ -29,7 +29,6 @@ #include "BufferViewVk.h" #include "RenderDeviceVk.h" #include "BufferViewBase.h" -#include "DescriptorHeap.h" #include "VulkanUtilities/VulkanObjectWrappers.h" namespace Diligent diff --git a/Graphics/GraphicsEngineVulkan/include/CommandContext.h b/Graphics/GraphicsEngineVulkan/include/CommandContext.h index a33b4213..640bb828 100644 --- a/Graphics/GraphicsEngineVulkan/include/CommandContext.h +++ b/Graphics/GraphicsEngineVulkan/include/CommandContext.h @@ -26,11 +26,11 @@ #include +#if 0 //#include "D3D12ResourceBase.h" #include "TextureViewVk.h" #include "TextureVk.h" #include "BufferVk.h" -#include "DescriptorHeap.h" namespace Diligent { @@ -58,14 +58,14 @@ namespace Diligent class CommandContext { public: - + /* CommandContext( IMemoryAllocator &MemAllocator, class CommandListManager& CmdListManager, GPUDescriptorHeap GPUDescriptorHeaps[], const Uint32 DynamicDescriptorAllocationChunkSize[]); ~CommandContext(void); -/* + // Submit the command buffer and reset it. This is encouraged to keep the GPU busy and reduce latency. // Taking too long to build command lists and submit them can idle the GPU. ID3D12GraphicsCommandList* Close(ID3D12CommandAllocator **ppAllocator); @@ -369,4 +369,5 @@ inline void CommandContext::SetDescriptorHeaps( ShaderDescriptorHeaps& Heaps ) } } */ -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h b/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h deleted file mode 100644 index b48fa909..00000000 --- a/Graphics/GraphicsEngineVulkan/include/DescriptorHeap.h +++ /dev/null @@ -1,532 +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. - */ - -// Descriptor heap management utilities. -// See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-descriptor-heaps/ for details - -#pragma once - -#include -#include -#include -#include -#include -//#include "ObjectBase.h" -//#include "VariableSizeGPUAllocationsManager.h" - -namespace Diligent -{ - -class DescriptorHeapAllocation; -class DescriptorHeapAllocationManager; -class RenderDeviceD3D12Impl; -// -class IDescriptorAllocator -{ -public: - // Allocate Count descriptors - virtual DescriptorHeapAllocation Allocate( uint32_t Count ) = 0; - virtual void Free(DescriptorHeapAllocation&& Allocation) = 0; - virtual Uint32 GetDescriptorSize()const = 0; -}; - - -// The class represents descriptor heap allocation (continuous descriptor range in a descriptor heap) -// -// m_FirstCpuHandle -// | -// | ~ ~ ~ ~ ~ X X X X X X X ~ ~ ~ ~ ~ ~ | D3D12 Descriptor Heap -// | -// m_FirstGpuHandle -// -class DescriptorHeapAllocation -{ -public: -#if 0 - // Creates null allocation - DescriptorHeapAllocation() : - m_NumHandles(1), // One null descriptor handle - m_pDescriptorHeap(nullptr), - m_DescriptorSize(0) - { - m_FirstCpuHandle.ptr = 0; - m_FirstGpuHandle.ptr = 0; - } - - // Initializes non-null allocation - DescriptorHeapAllocation( IDescriptorAllocator *pAllocator, - ID3D12DescriptorHeap *pHeap, - D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle, - D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle, - Uint32 NHandles, - Uint16 AllocationManagerId = static_cast(-1) ) : - m_FirstCpuHandle(CpuHandle), - m_FirstGpuHandle(GpuHandle), - m_pAllocator(pAllocator), - m_NumHandles(NHandles), - m_pDescriptorHeap(pHeap), - m_AllocationManagerId(AllocationManagerId) - { - VERIFY_EXPR(m_pAllocator != nullptr && m_pDescriptorHeap != nullptr); - auto DescriptorSize = m_pAllocator->GetDescriptorSize(); - VERIFY(DescriptorSize < std::numeric_limits::max(), "DescriptorSize exceeds allowed limit"); - m_DescriptorSize = static_cast( DescriptorSize ); - } - - // Move constructor (copy is not allowed) - DescriptorHeapAllocation(DescriptorHeapAllocation &&Allocation) : - m_FirstCpuHandle(Allocation.m_FirstCpuHandle), - m_FirstGpuHandle(Allocation.m_FirstGpuHandle), - m_NumHandles(Allocation.m_NumHandles), - m_pAllocator(std::move(Allocation.m_pAllocator)), - m_AllocationManagerId(std::move(Allocation.m_AllocationManagerId)), - m_pDescriptorHeap(std::move(Allocation.m_pDescriptorHeap) ), - m_DescriptorSize(std::move(Allocation.m_DescriptorSize) ) - { - Allocation.m_pAllocator = nullptr; - Allocation.m_FirstCpuHandle.ptr = 0; - Allocation.m_FirstGpuHandle.ptr = 0; - Allocation.m_NumHandles = 0; - Allocation.m_pDescriptorHeap = nullptr; - Allocation.m_DescriptorSize = 0; - Allocation.m_AllocationManagerId = static_cast(-1); - } - - // Move assignment (assignment is not allowed) - DescriptorHeapAllocation& operator = (DescriptorHeapAllocation &&Allocation) - { - m_FirstCpuHandle = Allocation.m_FirstCpuHandle; - m_FirstGpuHandle = Allocation.m_FirstGpuHandle; - m_NumHandles = Allocation.m_NumHandles; - m_pAllocator = std::move(Allocation.m_pAllocator); - m_AllocationManagerId = std::move(Allocation.m_AllocationManagerId); - m_pDescriptorHeap = std::move(Allocation.m_pDescriptorHeap); - m_DescriptorSize = std::move(Allocation.m_DescriptorSize); - - Allocation.m_FirstCpuHandle.ptr = 0; - Allocation.m_FirstGpuHandle.ptr = 0; - Allocation.m_NumHandles = 0; - Allocation.m_pAllocator = nullptr; - Allocation.m_pDescriptorHeap = nullptr; - Allocation.m_DescriptorSize = 0; - Allocation.m_AllocationManagerId = static_cast(-1); - - return *this; - } - - // Destructor automatically releases this allocation through the allocator - ~DescriptorHeapAllocation() - { - if(!IsNull() && m_pAllocator) - m_pAllocator->Free(std::move(*this)); - // Allocation must have been disposed by the allocator - VERIFY(IsNull(), "Non-null descriptor is being destroyed"); - } - - // Returns CPU descriptor handle at the specified offset - D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Uint32 Offset = 0) const - { - VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles); - - D3D12_CPU_DESCRIPTOR_HANDLE CPUHandle = m_FirstCpuHandle; - if (Offset != 0) - { - CPUHandle.ptr += m_DescriptorSize * Offset; - } - return CPUHandle; - } - - // Returns GPU descriptor handle at the specified offset - D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Uint32 Offset = 0) const - { - VERIFY_EXPR(Offset >= 0 && Offset < m_NumHandles); - D3D12_GPU_DESCRIPTOR_HANDLE GPUHandle = m_FirstGpuHandle; - if (Offset != 0) - { - GPUHandle.ptr += m_DescriptorSize * Offset; - } - return GPUHandle; - } - - // Returns pointer to D3D12 descriptor heap that contains this allocation - ID3D12DescriptorHeap *GetDescriptorHeap(){return m_pDescriptorHeap;} - - size_t GetNumHandles()const{return m_NumHandles;} - - bool IsNull() const { return m_FirstCpuHandle.ptr == 0; } - bool IsShaderVisible() const { return m_FirstGpuHandle.ptr != 0; } - size_t GetAllocationManagerId(){return m_AllocationManagerId;} - UINT GetDescriptorSize()const{return m_DescriptorSize;} - -private: - // No copies, only moves are allowed - DescriptorHeapAllocation(const DescriptorHeapAllocation&) = delete; - DescriptorHeapAllocation& operator= (const DescriptorHeapAllocation&) = delete; - - // First CPU descriptor handle in this allocation - D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCpuHandle = {0}; - - // First GPU descriptor handle in this allocation - D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGpuHandle = {0}; - - // Keep strong reference to the parent heap to make sure it is alive while allocation is alive - TOO EXPENSIVE - //RefCntAutoPtr m_pAllocator; - - // Pointer to the descriptor heap allocator that created this allocation - IDescriptorAllocator* m_pAllocator = nullptr; - - // Pointer to the D3D12 descriptor heap that contains descriptors in this allocation - ID3D12DescriptorHeap* m_pDescriptorHeap = nullptr; - - // Number of descriptors in the allocation - Uint32 m_NumHandles = 0; - - // Allocation manager ID. One allocator may support several - // allocation managers. This field is required to identify - // the manager within the allocator that was used to create - // this allocation - Uint16 m_AllocationManagerId = static_cast(-1); - - // Descriptor size - Uint16 m_DescriptorSize = 0; -#endif -}; - - -// The class performs suballocations within one D3D12 descriptor heap. -// It uses VariableSizeGPUAllocationsManager to manage free space in the heap -// -// | X X X X O O O X X O O X O O O O | D3D12 descriptor heap -// -// X - used descriptor -// O - available descriptor -// -class DescriptorHeapAllocationManager -{ -public: -#if 0 - // Creates a new D3D12 descriptor heap - DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, - RenderDeviceD3D12Impl *pDeviceD3D12Impl, - IDescriptorAllocator *pParentAllocator, - size_t ThisManagerId, - const D3D12_DESCRIPTOR_HEAP_DESC &HeapDesc); - - // Uses subrange of descriptors in the existing D3D12 descriptor heap - // that starts at offset FirstDescriptor and uses NumDescriptors descriptors - DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, - RenderDeviceD3D12Impl *pDeviceD3D12Impl, - IDescriptorAllocator *pParentAllocator, - size_t ThisManagerId, - ID3D12DescriptorHeap *pd3d12DescriptorHeap, - Uint32 FirstDescriptor, - Uint32 NumDescriptors); - - - // = default causes compiler error when instantiating std::vector::emplace_back() in Visual Studio 2015 (Version 14.0.23107.0 D14REL) - DescriptorHeapAllocationManager(DescriptorHeapAllocationManager&& rhs) : - m_FreeBlockManager(std::move(rhs.m_FreeBlockManager)), - m_HeapDesc(rhs.m_HeapDesc), - m_pd3d12DescriptorHeap(std::move(rhs.m_pd3d12DescriptorHeap)), - m_FirstCPUHandle(rhs.m_FirstCPUHandle), - m_FirstGPUHandle(rhs.m_FirstGPUHandle), - m_DescriptorSize(rhs.m_DescriptorSize), - m_NumDescriptorsInAllocation(rhs.m_NumDescriptorsInAllocation), - // Mutex is not movable - //m_AllocationMutex(std::move(rhs.m_AllocationMutex)) - m_pDeviceD3D12Impl(rhs.m_pDeviceD3D12Impl), - m_pParentAllocator(rhs.m_pParentAllocator), - m_ThisManagerId(rhs.m_ThisManagerId) - { - rhs.m_FirstCPUHandle.ptr = 0; - rhs.m_FirstGPUHandle.ptr = 0; - rhs.m_DescriptorSize = 0; - rhs.m_NumDescriptorsInAllocation = 0; - rhs.m_HeapDesc.NumDescriptors = 0; - rhs.m_pDeviceD3D12Impl = nullptr; - rhs.m_pParentAllocator = nullptr; - rhs.m_ThisManagerId = static_cast(-1); - } - - // No copies or move-assignments - DescriptorHeapAllocationManager& operator = (DescriptorHeapAllocationManager&& rhs) = delete; - DescriptorHeapAllocationManager(const DescriptorHeapAllocationManager&) = delete; - DescriptorHeapAllocationManager& operator = (const DescriptorHeapAllocationManager&) = delete; - - ~DescriptorHeapAllocationManager(); - - // Allocates Count descriptors - DescriptorHeapAllocation Allocate( uint32_t Count ); - - // Releases descriptor heap allocation. - // Note that the allocation is not released immediately, but - // added to the release queue in the allocations manager - void Free(DescriptorHeapAllocation&& Allocation); - - // Releases all stale allocation used by completed command lists - // The method takes the last known completed fence value N - // and releases all allocations whose associated fence value n <= N - void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue); - - size_t GetNumAvailableDescriptors()const{return m_FreeBlockManager.GetFreeSize();} - size_t GetNumStaleDescriptors()const { return m_FreeBlockManager.GetStaleAllocationsSize(); } - Uint32 GetMaxDescriptors()const { return m_NumDescriptorsInAllocation; } - -private: - // Allocations manager used to handle descriptor allocations within the heap - VariableSizeGPUAllocationsManager m_FreeBlockManager; - - // Heap description - D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; - - // Strong reference to D3D12 descriptor heap object - CComPtr m_pd3d12DescriptorHeap; - - // First CPU descriptor handle in the available descriptor range - D3D12_CPU_DESCRIPTOR_HANDLE m_FirstCPUHandle = {0}; - - // First GPU descriptor handle in the available descriptor range - D3D12_GPU_DESCRIPTOR_HANDLE m_FirstGPUHandle = {0}; - - UINT m_DescriptorSize = 0; - - // Number of descriptors in the allocation. - // If this manager was initialized as a subrange in the existing heap, - // this value may be different from m_HeapDesc.NumDescriptors - Uint32 m_NumDescriptorsInAllocation = 0; - - std::mutex m_AllocationMutex; - RenderDeviceD3D12Impl *m_pDeviceD3D12Impl = nullptr; - IDescriptorAllocator *m_pParentAllocator = nullptr; - - // External ID assigned to this descriptor allocations manager - size_t m_ThisManagerId = static_cast(-1); -#endif -}; - -// CPU descriptor heap is intended to provide storage for resource view descriptor handles -// It contains a pool of DescriptorHeapAllocationManager object instances, where every instance manages -// its own CPU-only D3D12 descriptor heap: -// -// m_HeapPool[0] m_HeapPool[1] m_HeapPool[2] -// | X X X X X X X X |, | X X X O O X X O |, | X O O O O O O O | -// -// X - used descriptor m_AvailableHeaps = {1,2} -// O - available descriptor -// -// Allocation routine goes through the list of managers that have available descriptors and tries to process -// the request using every manager. If there are no available managers or no manager was able to handle the request, -// the function creates a new descriptor heap manager and lets it handle the request -// -// Render device contains four CPUDescriptorHeap object instances (one for each D3D12 heap type). The heaps are accessed -// when a texture or a buffer view is created. -// -class CPUDescriptorHeap : public IDescriptorAllocator -{ -#if 0 -public: - // Initializes the heap - CPUDescriptorHeap(IMemoryAllocator &Allocator, - RenderDeviceD3D12Impl *pDeviceD3D12Impl, - Uint32 NumDescriptorsInHeap, - D3D12_DESCRIPTOR_HEAP_TYPE Type, - D3D12_DESCRIPTOR_HEAP_FLAGS Flags); - - CPUDescriptorHeap(const CPUDescriptorHeap&) = delete; - CPUDescriptorHeap(CPUDescriptorHeap&&) = delete; - CPUDescriptorHeap& operator = (const CPUDescriptorHeap&) = delete; - CPUDescriptorHeap& operator = (CPUDescriptorHeap&&) = delete; - - ~CPUDescriptorHeap(); - - virtual DescriptorHeapAllocation Allocate( uint32_t Count )override; - virtual void Free(DescriptorHeapAllocation&& Allocation)override; - virtual Uint32 GetDescriptorSize()const override{return m_DescriptorSize;} - - // Releases all stale allocation used by completed command lists - // The method takes the last known completed fence value N - // and releases all allocations whose associated fence value n <= N - void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue); - -protected: - - // Pool of descriptor heap managers - std::vector > m_HeapPool; - // Indices of available descriptor heap managers - std::set, STDAllocatorRawMem > m_AvailableHeaps; - IMemoryAllocator &m_MemAllocator; - - std::mutex m_AllocationMutex; - - D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; - RenderDeviceD3D12Impl *m_pDeviceD3D12Impl; - UINT m_DescriptorSize; - - // Maximum heap size during the application lifetime - for statistic purposes - Uint32 m_MaxHeapSize = 0; - Uint32 m_MaxStaleSize = 0; - Uint32 m_CurrentSize = 0; // This size does not count stale allocation -#endif -}; - -// GPU descriptor heap provides storage for shader-visible descriptors -// The heap contains single D3D12 descriptor heap that is broken into two parts. -// The first part stores static and mutable resource descriptor handles. -// The second part is intended to provide temporary storage for dynamic resources -// Space for dynamic resources is allocated in chunks, and then descriptors are suballocated within every -// chunk. DynamicSuballocationsManager facilitates this process -// -// -// static and mutable handles || dynamic space -// || chunk 0 chunk 1 chunk 2 unused -// | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O || -// | | -// suballocation suballocation -// within chunk 0 within chunk 1 -// -// Render device contains two GPUDescriptorHeap instances (CBV_SRV_UAV and SAMPLER). The heaps -// are used to allocate GPU-visible descriptors for shader resource binding objects. The heaps -// are also used by the command contexts (through DynamicSuballocationsManager to allocated dynamic descriptors) -// -// _______________________________________________________________________________________________________________________________ -// | Render Device | -// | | -// | m_CPUDescriptorHeaps[CBV_SRV_UAV] | X X X X X X X X |, | X X X X X X X X |, | X O O X O O O O | | -// | m_CPUDescriptorHeaps[SAMPLER] | X X X X O O O X |, | X O O X O O O O | | -// | m_CPUDescriptorHeaps[RTV] | X X X O O O O O |, | O O O O O O O O | | -// | m_CPUDescriptorHeaps[DSV] | X X X O X O X O | | -// | ctx1 ctx2 | -// | m_GPUDescriptorHeaps[CBV_SRV_UAV] | X O O X X O X O O O O X X X X O || | X X X O | | X X O O | | O O O O | O O O O || | -// | m_GPUDescriptorHeaps[SAMPLER] | X X O O X O X X X O O X O O O O || | X X O O | | X O O O | | O O O O | O O O O || | -// | | -// |_______________________________________________________________________________________________________________________________| -// -// ________________________________________________ ________________________________________________ -// |Device Context 1 | |Device Context 2 | -// | | | | -// | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] | | m_DynamicGPUDescriptorAllocator[CBV_SRV_UAV] | -// | m_DynamicGPUDescriptorAllocator[SAMPLER] | | m_DynamicGPUDescriptorAllocator[SAMPLER] | -// |________________________________________________| |________________________________________________| -// -class GPUDescriptorHeap : public IDescriptorAllocator -{ -public: -#if 0 - GPUDescriptorHeap(IMemoryAllocator &Allocator, - RenderDeviceD3D12Impl *pDevice, - Uint32 NumDescriptorsInHeap, - Uint32 NumDynamicDescriptors, - D3D12_DESCRIPTOR_HEAP_TYPE Type, - D3D12_DESCRIPTOR_HEAP_FLAGS Flags); -#endif - GPUDescriptorHeap(const GPUDescriptorHeap&) = delete; - GPUDescriptorHeap(GPUDescriptorHeap&&) = delete; - GPUDescriptorHeap& operator = (const GPUDescriptorHeap&) = delete; - GPUDescriptorHeap& operator = (GPUDescriptorHeap&&) = delete; - - ~GPUDescriptorHeap(); - - virtual DescriptorHeapAllocation Allocate( uint32_t Count )override; - virtual void Free(DescriptorHeapAllocation&& Allocation)override; - virtual Uint32 GetDescriptorSize()const override{return 0/*m_DescriptorSize*/;} -#if 0 - DescriptorHeapAllocation AllocateDynamic( uint32_t Count ); - - // Releases all stale allocation used by completed command lists - // The method takes the last known completed fence value N - // and releases all allocations whose associated fence value n <= N - void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue); - - const D3D12_DESCRIPTOR_HEAP_DESC &GetHeapDesc()const{return m_HeapDesc;} - Uint32 GetMaxStaticDescriptors()const { return m_HeapAllocationManager.GetMaxDescriptors(); } - Uint32 GetMaxDynamicDescriptors()const { return m_DynamicAllocationsManager.GetMaxDescriptors(); } - -protected: - - D3D12_DESCRIPTOR_HEAP_DESC m_HeapDesc; - CComPtr m_pd3d12DescriptorHeap; - - UINT m_DescriptorSize = 0; - - std::mutex m_AllocMutex, m_DynAllocMutex; - // Allocation manager for static/mutable part - DescriptorHeapAllocationManager m_HeapAllocationManager; - - // Allocation manager for dynamic part - DescriptorHeapAllocationManager m_DynamicAllocationsManager; - - RenderDeviceD3D12Impl *m_pDeviceD3D12; - Uint32 m_CurrentSize = 0; - // Maximum static/mutable part size during the application lifetime - for statistic purposes - Uint32 m_MaxHeapSize = 0; - Uint32 m_MaxStaleSize = 0; - Uint32 m_CurrentDynamicSize = 0; - // Maximum dynamic part size during the application lifetime - for statistic purposes - Uint32 m_MaxDynamicSize = 0; - Uint32 m_MaxDynamicStaleSize = 0; -#endif -}; - - -// The class facilitates allocation of dynamic descriptor handles. It requests a chunk of heap -// from the master GPU descriptor heap and then performs linear suballocation within the chunk -// At the end of the frame all allocations are disposed. - -// static and mutable handles || dynamic space -// || chunk 0 chunk 2 -// | || | X X X O | | O O O O | || GPU Descriptor Heap -// | | -// m_Suballocations[0] m_Suballocations[1] -// -class DynamicSuballocationsManager : public IDescriptorAllocator -{ -#if 0 -public: - DynamicSuballocationsManager(IMemoryAllocator &Allocator, GPUDescriptorHeap& ParentGPUHeap, Uint32 DynamicChunkSize); - - DynamicSuballocationsManager(const DynamicSuballocationsManager&) = delete; - DynamicSuballocationsManager(DynamicSuballocationsManager&&) = delete; - DynamicSuballocationsManager& operator = (const DynamicSuballocationsManager&) = delete; - DynamicSuballocationsManager& operator = (DynamicSuballocationsManager&&) = delete; - - void DiscardAllocations(Uint64 /*FenceValue*/); - - virtual DescriptorHeapAllocation Allocate( Uint32 Count )override; - virtual void Free(DescriptorHeapAllocation&& Allocation)override; - - virtual Uint32 GetDescriptorSize()const override{return m_ParentGPUHeap.GetDescriptorSize();} - -private: - // List of chunks allocated from the master GPU descriptor heap. All chunks are disposed at the end - // of the frame - std::vector > m_Suballocations; - - Uint32 m_CurrentSuballocationOffset = 0; - Uint32 m_DynamicChunkSize = 0; - - // Parent GPU descriptor heap that is used to allocate chunks - GPUDescriptorHeap &m_ParentGPUHeap; -#endif -}; - -} diff --git a/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h new file mode 100644 index 00000000..80291531 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/include/DescriptorPoolManager.h @@ -0,0 +1,119 @@ +/* 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. + */ + +// Descriptor heap management utilities. +// See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-descriptor-heaps/ for details + +#pragma once + +#include +#include +#include +#include "VulkanUtilities/VulkanDescriptorPool.h" + +namespace Diligent +{ + +class DescriptorPoolAllocation +{ +public: + DescriptorPoolAllocation(VkDescriptorSet _Set, + VulkanUtilities::VulkanDescriptorPool& _ParentPool) : + Set(_Set), + ParentPool(_ParentPool) + {} + DescriptorPoolAllocation(const DescriptorPoolAllocation&) = delete; + DescriptorPoolAllocation& operator = (const DescriptorPoolAllocation&) = delete; + + DescriptorPoolAllocation(DescriptorPoolAllocation&& rhs) : + Set(rhs.Set), + ParentPool(rhs.ParentPool) + { + rhs.Set = VK_NULL_HANDLE; + } + DescriptorPoolAllocation& operator = (DescriptorPoolAllocation&&) = delete; + + ~DescriptorPoolAllocation() + { + VERIFY(Set == VK_NULL_HANDLE, "Allocation must be explicitly disposed through DescriptorPoolManager::DisposeAllocation"); + } + + VkDescriptorSet GetVkDescriptorSet()const {return Set;} + +private: + friend class DescriptorPoolManager; + VkDescriptorSet Set; + VulkanUtilities::VulkanDescriptorPool& ParentPool; +}; + +class DescriptorPoolManager +{ +public: + DescriptorPoolManager(std::shared_ptr LogicalDevice, + std::vector PoolSizes, + uint32_t MaxSets, + bool IsThreadSafe)noexcept: + m_LogicalDevice(std::move(LogicalDevice)), + m_PoolSizes(std::move(PoolSizes)), + m_MaxSets(MaxSets), + m_IsThreadSafe(IsThreadSafe) + { + CreateNewPool(); + } + + // Move constructor must be noexcept, otherwise vector 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_IsThreadSafe(std::move(rhs.m_IsThreadSafe)), + //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(const DescriptorPoolManager&) = delete; + DescriptorPoolManager& operator = (const DescriptorPoolManager&) = delete; + DescriptorPoolManager& operator = (DescriptorPoolManager&&) = delete; + + DescriptorPoolAllocation Allocate(VkDescriptorSetLayout SetLayout); + void FreeAllocation(DescriptorPoolAllocation&& Allocation); + void DisposeAllocations(uint64_t FenceValue); + void ReleaseStaleAllocations(uint64_t LastCompletedFence); + +private: + void CreateNewPool(); + + const std::vector m_PoolSizes; + const uint32_t m_MaxSets; + const bool m_IsThreadSafe; + + std::mutex m_Mutex; + std::shared_ptr m_LogicalDevice; + std::deque m_DescriptorPools; + std::vector m_ReleasedAllocations; +}; + +} diff --git a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h index 5751b35b..483845c2 100644 --- a/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h +++ b/Graphics/GraphicsEngineVulkan/include/RenderDeviceVkImpl.h @@ -29,7 +29,7 @@ #include "RenderDeviceVk.h" #include "RenderDeviceBase.h" -#include "DescriptorHeap.h" +#include "DescriptorPoolManager.h" #include "CommandContext.h" #include "DynamicUploadHeap.h" #include "Atomics.h" @@ -128,17 +128,10 @@ private: std::unique_ptr m_PhysicalDevice; std::shared_ptr m_LogicalVkDevice; + std::mutex m_CmdQueueMutex; RefCntAutoPtr m_pCommandQueue; EngineVkAttribs m_EngineAttribs; -#if 0 - CPUDescriptorHeap m_CPUDescriptorHeaps[Vk_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; - GPUDescriptorHeap m_GPUDescriptorHeaps[2]; // Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV == 0 - // Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER == 1 - - const Uint32 m_DynamicDescriptorAllocationChunkSize[2]; -#endif - std::mutex m_CmdQueueMutex; Atomics::AtomicInt64 m_FrameNumber; Atomics::AtomicInt64 m_NextCmdListNumber; @@ -197,6 +190,13 @@ private: std::mutex m_StaleObjectsMutex; std::deque< ReleaseQueueElemType, STDAllocatorRawMem > m_StaleVkObjects; FramebufferCache m_FramebufferCache; + + // [0] - Main descriptor pool + // [1] - Immediate context dynamic descriptor pool + // [2+] - Deferred context dynamic descriptor pool + std::vector > m_DescriptorPools; + + #if 0 std::mutex m_UploadHeapMutex; typedef std::unique_ptr > UploadHeapPoolElemType; diff --git a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h index 23b40445..a05433e8 100644 --- a/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h +++ b/Graphics/GraphicsEngineVulkan/include/VulkanUtilities/VulkanDescriptorPool.h @@ -35,11 +35,11 @@ namespace VulkanUtilities { public: VulkanDescriptorPool(std::shared_ptr LogicalDevice, - const VkDescriptorPoolCreateInfo &DescriptorPoolCI); - VulkanDescriptorPool(const VulkanDescriptorPool&) = delete; - VulkanDescriptorPool(VulkanDescriptorPool&&) = delete; + const VkDescriptorPoolCreateInfo &DescriptorPoolCI)noexcept; + VulkanDescriptorPool (const VulkanDescriptorPool&) = delete; VulkanDescriptorPool& operator = (const VulkanDescriptorPool&) = delete; - VulkanDescriptorPool& operator = (VulkanDescriptorPool&&) = delete; + VulkanDescriptorPool (VulkanDescriptorPool&&) = default; + VulkanDescriptorPool& operator = (VulkanDescriptorPool&&) = default; ~VulkanDescriptorPool(); VkDescriptorSet AllocateDescriptorSet(VkDescriptorSetLayout SetLayout, const char* DebugName = ""); diff --git a/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp index 0b254cfc..46deb474 100644 --- a/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp +++ b/Graphics/GraphicsEngineVulkan/src/CommandContext.cpp @@ -26,6 +26,7 @@ #include "TextureVkImpl.h" #include "BufferVkImpl.h" +#if 0 namespace Diligent { @@ -318,3 +319,4 @@ DescriptorHeapAllocation CommandContext::AllocateDynamicGPUVisibleDescriptor( Vk #endif } +#endif \ No newline at end of file diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp deleted file mode 100644 index 6967f33f..00000000 --- a/Graphics/GraphicsEngineVulkan/src/DescriptorHeap.cpp +++ /dev/null @@ -1,428 +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 "pch.h" -#include "DescriptorHeap.h" -#include "RenderDeviceVkImpl.h" - -namespace Diligent -{ - -#if 0 -// Creates a new descriptor heap and reference the entire heap -DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, - RenderDeviceVkImpl *pDeviceVkImpl, - IDescriptorAllocator *pParentAllocator, - size_t ThisManagerId, - const Vk_DESCRIPTOR_HEAP_DESC &HeapDesc) : - m_FreeBlockManager(HeapDesc.NumDescriptors, Allocator), - m_NumDescriptorsInAllocation(HeapDesc.NumDescriptors), - m_HeapDesc(HeapDesc), - m_pDeviceVkImpl(pDeviceVkImpl), - m_pParentAllocator(pParentAllocator), - m_ThisManagerId(ThisManagerId) -{ - auto pDevice = pDeviceVkImpl->GetVkDevice(); - - m_FirstCPUHandle.ptr = 0; - m_FirstGPUHandle.ptr = 0; - m_DescriptorSize = pDevice->GetDescriptorHandleIncrementSize(HeapDesc.Type); - - pDevice->CreateDescriptorHeap(&m_HeapDesc, __uuidof(m_pVkDescriptorHeap), reinterpret_cast(static_cast(&m_pVkDescriptorHeap))); - m_FirstCPUHandle = m_pVkDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); - if(m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) - m_FirstGPUHandle = m_pVkDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); -} - -// Uses subrange of descriptors in the existing Vk descriptor heap -// that starts at offset FirstDescriptor and uses NumDescriptors descriptors -DescriptorHeapAllocationManager::DescriptorHeapAllocationManager(IMemoryAllocator &Allocator, - RenderDeviceVkImpl *pDeviceVkImpl, - IDescriptorAllocator *pParentAllocator, - size_t ThisManagerId, - IVkDescriptorHeap *pVkDescriptorHeap, - Uint32 FirstDescriptor, - Uint32 NumDescriptors): - m_FreeBlockManager(NumDescriptors, Allocator), - m_NumDescriptorsInAllocation(NumDescriptors), - m_pDeviceVkImpl(pDeviceVkImpl), - m_pParentAllocator(pParentAllocator), - m_ThisManagerId(ThisManagerId), - m_pVkDescriptorHeap(pVkDescriptorHeap) -{ - m_HeapDesc = m_pVkDescriptorHeap->GetDesc(); - m_DescriptorSize = pDeviceVkImpl->GetVkDevice()->GetDescriptorHandleIncrementSize(m_HeapDesc.Type); - - m_FirstCPUHandle = pVkDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); - m_FirstCPUHandle.ptr += m_DescriptorSize * FirstDescriptor; - - if (m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) - { - m_FirstGPUHandle = pVkDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); - m_FirstGPUHandle.ptr += m_DescriptorSize * FirstDescriptor; - } -} - - -DescriptorHeapAllocationManager::~DescriptorHeapAllocationManager() -{ - VERIFY(m_FreeBlockManager.GetFreeSize() == m_NumDescriptorsInAllocation, "Not all descriptors were released"); -} - -DescriptorHeapAllocation DescriptorHeapAllocationManager::Allocate(uint32_t Count) -{ - std::lock_guard LockGuard(m_AllocationMutex); - // Methods of VariableSizeGPUAllocationsManager class are not thread safe! - - // Use variable-size GPU allocations manager to allocate the requested number of descriptors - auto DescriptorHandleOffset = m_FreeBlockManager.Allocate(Count); - if (DescriptorHandleOffset == VariableSizeGPUAllocationsManager::InvalidOffset) - { - return DescriptorHeapAllocation(); - } - - // Compute the first CPU and GPU descriptor handles in the allocation by - // offseting the first CPU and GPU descriptor handle in the range - auto CPUHandle = m_FirstCPUHandle; - CPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize; - - auto GPUHandle = m_FirstGPUHandle; // Will be null if the heap is not GPU-visible - if(m_HeapDesc.Flags & Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE) - GPUHandle.ptr += DescriptorHandleOffset * m_DescriptorSize; - - VERIFY(m_ThisManagerId < std::numeric_limits::max(), "ManagerID exceeds 16-bit range"); - return DescriptorHeapAllocation( m_pParentAllocator, m_pVkDescriptorHeap, CPUHandle, GPUHandle, Count, static_cast(m_ThisManagerId)); -} - -void DescriptorHeapAllocationManager::Free(DescriptorHeapAllocation&& Allocation) -{ - std::lock_guard LockGuard(m_AllocationMutex); - // Methods of VariableSizeGPUAllocationsManager class are not thread safe! - - VERIFY(Allocation.GetAllocationManagerId() == m_ThisManagerId, "Invalid descriptor heap manager Id"); - - auto DescriptorOffset = (Allocation.GetCpuHandle().ptr - m_FirstCPUHandle.ptr) / m_DescriptorSize; - - // Note that the allocation is not released immediately, but added to the release queue in the allocations manager - - // The following basic requirement guarantees correctness of resource deallocation: - // - // A resource is never released before the last draw command referencing it is invoked on the immediate context - // - // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/ - // - // If basic requirement is met, GetNextFenceValue() will never return a number that is less than the fence value - // associated with the last command list that references descriptors from the allocation - m_FreeBlockManager.Free(DescriptorOffset, Allocation.GetNumHandles(), m_pDeviceVkImpl->GetNextFenceValue()); - - // Clear the allocation - Allocation = DescriptorHeapAllocation(); -} - -void DescriptorHeapAllocationManager::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue) -{ - std::lock_guard LockGuard(m_AllocationMutex); - // Methods of VariableSizeGPUAllocationsManager class are not thread safe! - - m_FreeBlockManager.ReleaseStaleAllocations(LastCompletedFenceValue); -} - - - - -// -// CPUDescriptorHeap implementation -// -CPUDescriptorHeap::CPUDescriptorHeap(IMemoryAllocator &Allocator, RenderDeviceVkImpl *pDeviceVkImpl, Uint32 NumDescriptorsInHeap, Vk_DESCRIPTOR_HEAP_TYPE Type, Vk_DESCRIPTOR_HEAP_FLAGS Flags) : - m_pDeviceVkImpl(pDeviceVkImpl), - m_MemAllocator(Allocator), - m_HeapPool(STD_ALLOCATOR_RAW_MEM(DescriptorHeapAllocationManager, GetRawAllocator(), "Allocator for vector")), - m_AvailableHeaps(STD_ALLOCATOR_RAW_MEM(size_t, GetRawAllocator(), "Allocator for set")) -{ - m_HeapDesc.Type = Type; - m_HeapDesc.NodeMask = 1; - m_HeapDesc.NumDescriptors = NumDescriptorsInHeap; - m_HeapDesc.Flags = Flags; - - m_DescriptorSize = m_pDeviceVkImpl->GetVkDevice()->GetDescriptorHandleIncrementSize(Type); -} - -CPUDescriptorHeap::~CPUDescriptorHeap() -{ - VERIFY(m_CurrentSize == 0, "Not all allocations released" ); - - VERIFY(m_AvailableHeaps.size() == m_HeapPool.size(), "Not all descriptor heap pools are released"); - Uint32 TotalDescriptors = 0; - for (auto HeapPoolIt = m_HeapPool.begin(); HeapPoolIt != m_HeapPool.end(); ++HeapPoolIt) - { - VERIFY(HeapPoolIt->GetNumAvailableDescriptors() == HeapPoolIt->GetMaxDescriptors(), "Not all descriptors in the descriptor pool are released"); - TotalDescriptors += HeapPoolIt->GetMaxDescriptors(); - } - TotalDescriptors = std::max(TotalDescriptors, 1u); - - LOG_INFO_MESSAGE(GetVkDescriptorHeapTypeLiteralName(m_HeapDesc.Type), " CPU heap max size: ", m_MaxHeapSize, " (", m_MaxHeapSize*100/ TotalDescriptors, "%) " - ". Max stale size: ", m_MaxStaleSize, " (", m_MaxStaleSize * 100 / TotalDescriptors, "%)"); -} - -DescriptorHeapAllocation CPUDescriptorHeap::Allocate( uint32_t Count ) -{ - std::lock_guard LockGuard(m_AllocationMutex); - // Note that every DescriptorHeapAllocationManager object instance is itslef - // thread-safe. Nested mutexes cannot cause a deadlock - - DescriptorHeapAllocation Allocation; - // Go through all descriptor heap managers that have free descriptors - auto AvailableHeapIt = m_AvailableHeaps.begin(); - while( AvailableHeapIt != m_AvailableHeaps.end() ) - { - auto NextIt = AvailableHeapIt; - ++NextIt; - // Try to allocate descriptor using the current descriptor heap manager - Allocation = m_HeapPool[*AvailableHeapIt].Allocate(Count); - // Remove the manager from the pool if it has no more available descriptors - if (m_HeapPool[*AvailableHeapIt].GetNumAvailableDescriptors() == 0) - m_AvailableHeaps.erase(*AvailableHeapIt); - - // Terminate the loop if descriptor was successfully allocated, otherwise - // go to the next manager - if(Allocation.GetCpuHandle().ptr != 0) - break; - AvailableHeapIt = NextIt; - } - - // If there were no available descriptor heap managers or no manager was able - // to suffice the allocation request, create a new manager - if(Allocation.GetCpuHandle().ptr == 0) - { - // Make sure the heap is large enough to accomodate the requested number of descriptors - if(Count > m_HeapDesc.NumDescriptors) - { - LOG_WARNING_MESSAGE("Number of requested CPU descriptors handles (", Count, ") exceeds the descriptor heap size (", m_HeapDesc.NumDescriptors,"). Increasing the number of descriptors in the heap"); - } - m_HeapDesc.NumDescriptors = std::max(m_HeapDesc.NumDescriptors, static_cast(Count)); - // Create a new descriptor heap manager. Note that this constructor creates a new Vk descriptor - // heap and references the entire heap. Pool index is used as manager ID - m_HeapPool.emplace_back(m_MemAllocator, m_pDeviceVkImpl, this, m_HeapPool.size(), m_HeapDesc); - auto NewHeapIt = m_AvailableHeaps.insert(m_HeapPool.size()-1); - - // Use the new manager to allocate descriptor handles - Allocation = m_HeapPool[*NewHeapIt.first].Allocate(Count); - } - - m_CurrentSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0; - m_MaxHeapSize = std::max(m_MaxHeapSize, m_CurrentSize); - - return Allocation; -} - -void CPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation) -{ - // Method is called from ~DescriptorHeapAllocation() - std::lock_guard LockGuard(m_AllocationMutex); - auto ManagerId = Allocation.GetAllocationManagerId(); - m_CurrentSize -= static_cast(Allocation.GetNumHandles()); - m_HeapPool[ManagerId].Free(std::move(Allocation)); -} - -void CPUDescriptorHeap::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue) -{ - std::lock_guard LockGuard(m_AllocationMutex); - size_t StaleSize = 0; - for (size_t HeapManagerInd = 0; HeapManagerInd < m_HeapPool.size(); ++HeapManagerInd) - { - // Update size before releasing stale allocations - StaleSize += m_HeapPool[HeapManagerInd].GetNumStaleDescriptors(); - - m_HeapPool[HeapManagerInd].ReleaseStaleAllocations(LastCompletedFenceValue); - // Return the manager to the pool of available managers if it has available descriptors - if(m_HeapPool[HeapManagerInd].GetNumAvailableDescriptors() > 0) - m_AvailableHeaps.insert(HeapManagerInd); - } - m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast(StaleSize)); -} - - - - -GPUDescriptorHeap::GPUDescriptorHeap(IMemoryAllocator &Allocator, - RenderDeviceVkImpl *pDevice, - Uint32 NumDescriptorsInHeap, - Uint32 NumDynamicDescriptors, - Vk_DESCRIPTOR_HEAP_TYPE Type, - Vk_DESCRIPTOR_HEAP_FLAGS Flags) : - m_pDeviceVk(pDevice), - m_HeapDesc - { - Type, - NumDescriptorsInHeap + NumDynamicDescriptors, - Flags, - 1 // UINT NodeMask; - }, - m_pVkDescriptorHeap([&]{ - CComPtr pHeap; - pDevice->GetVkDevice()->CreateDescriptorHeap(&m_HeapDesc, __uuidof(pHeap), reinterpret_cast(&pHeap)); - return pHeap; - }()), - m_DescriptorSize( pDevice->GetVkDevice()->GetDescriptorHandleIncrementSize(Type) ), - m_HeapAllocationManager(Allocator, pDevice, this, 0, m_pVkDescriptorHeap, 0, NumDescriptorsInHeap), - m_DynamicAllocationsManager(Allocator, pDevice, this, 1, m_pVkDescriptorHeap, NumDescriptorsInHeap, NumDynamicDescriptors ) -{ -} - -GPUDescriptorHeap::~GPUDescriptorHeap() -{ - auto StaticSize = m_HeapAllocationManager.GetMaxDescriptors(); - auto DynamicSize = m_DynamicAllocationsManager.GetMaxDescriptors(); - LOG_INFO_MESSAGE(GetVkDescriptorHeapTypeLiteralName(m_HeapDesc.Type), " GPU heap max allocated size (static|dynamic): ", - m_MaxHeapSize, " (", m_MaxHeapSize * 100 / StaticSize,"%) | ", - m_MaxDynamicSize, " (", m_MaxDynamicSize * 100 / DynamicSize, "%). Max stale size (static|dynamic): ", - m_MaxStaleSize, " (", m_MaxStaleSize * 100 / StaticSize, "%) | ", - m_MaxDynamicStaleSize, " (", m_MaxDynamicStaleSize * 100 / DynamicSize, "%)"); -} - -DescriptorHeapAllocation GPUDescriptorHeap::Allocate(uint32_t Count) -{ - VERIFY_EXPR(Count > 0); - // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe - std::lock_guard LockGuard(m_AllocMutex); - DescriptorHeapAllocation Allocation = m_HeapAllocationManager.Allocate(Count); - VERIFY(!Allocation.IsNull(), "Failed to allocate ", Count, " GPU descriptors"); - - m_CurrentSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0; - m_MaxHeapSize = std::max(m_MaxHeapSize, m_CurrentSize); - - return Allocation; -} - -DescriptorHeapAllocation GPUDescriptorHeap::AllocateDynamic(uint32_t Count) -{ - VERIFY_EXPR(Count > 0); - // Note: this mutex may be redundant as DescriptorHeapAllocationManager::Allocate() is itself thread-safe - std::lock_guard LockGuard(m_DynAllocMutex); - DescriptorHeapAllocation Allocation = m_DynamicAllocationsManager.Allocate(Count); - VERIFY(!Allocation.IsNull(), "Failed to allocate ", Count, " dynamic GPU descriptors"); - - m_CurrentDynamicSize += (Allocation.GetCpuHandle().ptr != 0) ? Count : 0; - m_MaxDynamicSize = std::max(m_MaxDynamicSize, m_CurrentDynamicSize); - - return Allocation; -} - -void GPUDescriptorHeap::Free(DescriptorHeapAllocation&& Allocation) -{ - auto MgrId = Allocation.GetAllocationManagerId(); - VERIFY(MgrId == 0 || MgrId == 1, "Unexpected allocation manager ID"); - - // Note: mutexex may be redundant as DescriptorHeapAllocationManager::Free() is itself thread-safe - if(MgrId == 0) - { - std::lock_guard LockGuard(m_AllocMutex); - m_CurrentSize -= static_cast(Allocation.GetNumHandles()); - m_HeapAllocationManager.Free(std::move(Allocation)); - } - else - { - std::lock_guard LockGuard(m_DynAllocMutex); - m_CurrentDynamicSize -= static_cast(Allocation.GetNumHandles()); - m_DynamicAllocationsManager.Free(std::move(Allocation)); - } -} - -void GPUDescriptorHeap::ReleaseStaleAllocations(Uint64 LastCompletedFenceValue) -{ - { - std::lock_guard LockGuard(m_AllocMutex); - m_MaxStaleSize = std::max(m_MaxStaleSize, static_cast(m_HeapAllocationManager.GetNumStaleDescriptors())); - m_HeapAllocationManager.ReleaseStaleAllocations(LastCompletedFenceValue); - } - - { - std::lock_guard LockGuard(m_DynAllocMutex); - m_MaxDynamicStaleSize = std::max(m_MaxDynamicStaleSize, static_cast(m_DynamicAllocationsManager.GetNumStaleDescriptors())); - m_DynamicAllocationsManager.ReleaseStaleAllocations(LastCompletedFenceValue); - } -} - - - - - -DynamicSuballocationsManager::DynamicSuballocationsManager(IMemoryAllocator &Allocator, GPUDescriptorHeap& ParentGPUHeap, Uint32 DynamicChunkSize) : - m_ParentGPUHeap(ParentGPUHeap), - m_DynamicChunkSize(DynamicChunkSize), - m_Suballocations(STD_ALLOCATOR_RAW_MEM(DescriptorHeapAllocation, GetRawAllocator(), "Allocator for vector")) -{ -} - -void DynamicSuballocationsManager::DiscardAllocations(Uint64 /*FenceValue*/) -{ - // Clear the list and dispose all allocated chunks of GPU descriptor heap. - // The chunks will be added to the release queue in the allocations manager - m_Suballocations.clear(); -} - -DescriptorHeapAllocation DynamicSuballocationsManager::Allocate(Uint32 Count) -{ - // This method is intentionally lock-free as it is expected to - // be called through device context from single thread only - - // Check if there are no chunks or the last chunk does not have enough space - if( m_Suballocations.empty() || - m_CurrentSuballocationOffset + Count > m_Suballocations.back().GetNumHandles() ) - { - // Request a new chunk from the parent GPU descriptor heap - auto SuballocationSize = std::max(m_DynamicChunkSize, Count); - auto NewDynamicSubAllocation = m_ParentGPUHeap.AllocateDynamic(SuballocationSize); - if (NewDynamicSubAllocation.GetCpuHandle().ptr == 0) - { - LOG_ERROR_MESSAGE("Failed to suballocate region for dynamic descriptors"); - return DescriptorHeapAllocation(); - } - m_Suballocations.emplace_back(std::move(NewDynamicSubAllocation)); - m_CurrentSuballocationOffset = 0; - } - - // Perform suballocation from the last chunk - auto &CurrentSuballocation = m_Suballocations.back(); - - auto ManagerId = CurrentSuballocation.GetAllocationManagerId(); - VERIFY(ManagerId < std::numeric_limits::max(), "ManagerID exceed allowed limit"); - DescriptorHeapAllocation Allocation( this, - CurrentSuballocation.GetDescriptorHeap(), - CurrentSuballocation.GetCpuHandle(m_CurrentSuballocationOffset), - CurrentSuballocation.GetGpuHandle(m_CurrentSuballocationOffset), - Count, - static_cast(ManagerId) ); - m_CurrentSuballocationOffset += Count; - - return Allocation; -} - -void DynamicSuballocationsManager::Free(DescriptorHeapAllocation&& Allocation) -{ - // Do nothing. Dynamic allocations are not disposed individually, but as whole chunks at the end of the frame - Allocation = DescriptorHeapAllocation(); -} -#endif - -} diff --git a/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp new file mode 100644 index 00000000..f10a0a74 --- /dev/null +++ b/Graphics/GraphicsEngineVulkan/src/DescriptorPoolManager.cpp @@ -0,0 +1,110 @@ +/* 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 "pch.h" +#include "DescriptorPoolManager.h" +#include "RenderDeviceVkImpl.h" + +namespace Diligent +{ + +void DescriptorPoolManager::CreateNewPool() +{ + VkDescriptorPoolCreateInfo PoolCI = {}; + PoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + PoolCI.pNext = nullptr; + // 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.maxSets = m_MaxSets; + PoolCI.poolSizeCount = static_cast(m_PoolSizes.size()); + PoolCI.pPoolSizes = m_PoolSizes.data(); + m_DescriptorPools.emplace_front(m_LogicalDevice, PoolCI); +} + +DescriptorPoolAllocation DescriptorPoolManager::Allocate(VkDescriptorSetLayout SetLayout) +{ + std::unique_lock Lock(m_Mutex, std::defer_lock); + if (m_IsThreadSafe) + Lock.lock(); + + // Try all pools starting from the frontmost + for(auto it = m_DescriptorPools.begin(); it != m_DescriptorPools.end(); ++it) + { + auto Set = it->AllocateDescriptorSet(SetLayout); + if(Set != VK_NULL_HANDLE) + { + // Move the pool to the front + if(it != m_DescriptorPools.begin()) + { + std::swap(*it, m_DescriptorPools.front()); + } + return {Set, *it}; + } + } + + // Failed to allocate descriptor from existing pools -> create a new one + CreateNewPool(); + LOG_INFO_MESSAGE("Allocated new descriptor pool"); + + auto Set = m_DescriptorPools.front().AllocateDescriptorSet(SetLayout); + VERIFY(Set != VK_NULL_HANDLE, "Failed to allocate descriptor set"); + + return {Set, m_DescriptorPools.front() }; +} + +void DescriptorPoolManager::FreeAllocation(DescriptorPoolAllocation&& Allocation) +{ + std::unique_lock Lock(m_Mutex, std::defer_lock); + if (m_IsThreadSafe) + Lock.lock(); + + m_ReleasedAllocations.emplace_back(std::move(Allocation)); +} + +void DescriptorPoolManager::DisposeAllocations(uint64_t FenceValue) +{ + std::unique_lock Lock(m_Mutex, std::defer_lock); + if (m_IsThreadSafe) + Lock.lock(); + + for(auto &Allocation : m_ReleasedAllocations) + { + Allocation.ParentPool.DisposeDescriptorSet(Allocation.Set, FenceValue); + Allocation.Set = VK_NULL_HANDLE; + } + m_ReleasedAllocations.clear(); +} + +void DescriptorPoolManager::ReleaseStaleAllocations(uint64_t LastCompletedFence) +{ + std::unique_lock Lock(m_Mutex, std::defer_lock); + if (m_IsThreadSafe) + Lock.lock(); + + for(auto &Pool : m_DescriptorPools) + Pool.ReleaseDiscardedSets(LastCompletedFence); +} + +} diff --git a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp index 3d77fa07..899a72fa 100644 --- a/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp +++ b/Graphics/GraphicsEngineVulkan/src/RenderDeviceVkImpl.cpp @@ -53,29 +53,12 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, m_FrameNumber(0), m_NextCmdListNumber(0), /*m_CmdListManager(this), - m_CPUDescriptorHeaps - { - {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[0], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Vk_DESCRIPTOR_HEAP_FLAG_NONE}, - {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[1], Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, Vk_DESCRIPTOR_HEAP_FLAG_NONE}, - {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[2], Vk_DESCRIPTOR_HEAP_TYPE_RTV, Vk_DESCRIPTOR_HEAP_FLAG_NONE}, - {RawMemAllocator, this, CreationAttribs.CPUDescriptorHeapAllocationSize[3], Vk_DESCRIPTOR_HEAP_TYPE_DSV, Vk_DESCRIPTOR_HEAP_FLAG_NONE} - }, - m_GPUDescriptorHeaps - { - {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[0], CreationAttribs.GPUDescriptorHeapDynamicSize[0], Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}, - {RawMemAllocator, this, CreationAttribs.GPUDescriptorHeapSize[1], CreationAttribs.GPUDescriptorHeapDynamicSize[1], Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER, Vk_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE} - }, - m_DynamicDescriptorAllocationChunkSize - { - CreationAttribs.DynamicDescriptorAllocationChunkSize[0], // Vk_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV - CreationAttribs.DynamicDescriptorAllocationChunkSize[1] // Vk_DESCRIPTOR_HEAP_TYPE_SAMPLER - }, m_ContextPool(STD_ALLOCATOR_RAW_MEM(ContextPoolElemType, GetRawAllocator(), "Allocator for vector>")), m_AvailableContexts(STD_ALLOCATOR_RAW_MEM(CommandContext*, GetRawAllocator(), "Allocator for vector")),*/ m_VkObjReleaseQueue(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue")), - m_StaleVkObjects(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue")),/*, - m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector>")) - */ + m_StaleVkObjects(STD_ALLOCATOR_RAW_MEM(ReleaseQueueElemType, GetRawAllocator(), "Allocator for queue")), + m_DescriptorPools(STD_ALLOCATOR_RAW_MEM(DescriptorPoolManager, GetRawAllocator(), "Allocator for vector")), + //m_UploadHeaps(STD_ALLOCATOR_RAW_MEM(UploadHeapPoolElemType, GetRawAllocator(), "Allocator for vector>")), m_CmdBufferPool(m_LogicalVkDevice->GetSharedPtr(), pCmdQueue->GetQueueFamilyIndex(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT), m_FramebufferCache(*this) { @@ -86,6 +69,46 @@ RenderDeviceVkImpl :: RenderDeviceVkImpl(IReferenceCounters *pRefCounters, m_DeviceCaps.bMultithreadedResourceCreationSupported = True; for(int fmt = 1; fmt < m_TextureFormatsInfo.size(); ++fmt) m_TextureFormatsInfo[fmt].Supported = true; // We will test every format on a specific hardware device + + m_DescriptorPools.reserve(2 + NumDeferredContexts); + m_DescriptorPools.emplace_back( + LogicalDevice, + std::vector{ + {VK_DESCRIPTOR_TYPE_SAMPLER, CreationAttribs.MainDescriptorPoolSize.NumSeparateSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, CreationAttribs.MainDescriptorPoolSize.NumCombinedSamplerDescriptors}, + {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, CreationAttribs.MainDescriptorPoolSize.NumSampledImageDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, CreationAttribs.MainDescriptorPoolSize.NumStorageImageDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, CreationAttribs.MainDescriptorPoolSize.NumUniformTexelBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, CreationAttribs.MainDescriptorPoolSize.NumStorageTexelBufferDescriptors}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, CreationAttribs.MainDescriptorPoolSize.NumUniformBufferDescriptors }, + {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, CreationAttribs.MainDescriptorPoolSize.NumStorageBufferDescriptors }, + //{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, CreationAttribs.MainDescriptorPoolSize.NumUniformBufferDescriptors }, + //{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, CreationAttribs.MainDescriptorPoolSize.NumStorageBufferDescriptors }, + }, + CreationAttribs.MainDescriptorPoolSize.MaxDescriptorSets, + true // Thread-safe + ); + + for(Uint32 ctx = 0; ctx < 1 + NumDeferredContexts; ++ctx) + { + m_DescriptorPools.emplace_back( + LogicalDevice, + std::vector{ + {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 // Dynamic descriptor pools need not to be thread-safe + ); + } } RenderDeviceVkImpl::~RenderDeviceVkImpl() @@ -313,18 +336,15 @@ void RenderDeviceVkImpl::FinishFrame(bool ReleaseAllResources) } } - for(Uint32 CPUHeap=0; CPUHeap < _countof(m_CPUDescriptorHeaps); ++CPUHeap) +#endif + { // This is OK if other thread disposes descriptor heap allocation at this time // The allocation will be registered as part of the current frame - m_CPUDescriptorHeaps[CPUHeap].ReleaseStaleAllocations(CompletedFenceValue); - } - - for(Uint32 GPUHeap=0; GPUHeap < _countof(m_GPUDescriptorHeaps); ++GPUHeap) - { - m_GPUDescriptorHeaps[GPUHeap].ReleaseStaleAllocations(CompletedFenceValue); + for(auto &Pool : m_DescriptorPools) + Pool.DisposeAllocations(NextFenceValue); } -#endif + // Discard all remaining objects. This is important to do if there were // no command lists submitted during the frame DiscardStaleVkObjects(CmdListNumber, NextFenceValue); @@ -430,17 +450,25 @@ void RenderDeviceVkImpl::DiscardStaleVkObjects(Uint64 CmdListNumber, Uint64 Fenc void RenderDeviceVkImpl::ProcessReleaseQueue(Uint64 CompletedFenceValue) { - std::lock_guard LockGuard(m_ReleaseQueueMutex); + { + std::lock_guard LockGuard(m_ReleaseQueueMutex); + + // Release all objects whose associated fence value is at most CompletedFenceValue + while (!m_VkObjReleaseQueue.empty()) + { + auto &FirstObj = m_VkObjReleaseQueue.front(); + if (FirstObj.first <= CompletedFenceValue) + m_VkObjReleaseQueue.pop_front(); + else + break; + } + } - // Release all objects whose associated fence value is at most CompletedFenceValue - // See http://diligentgraphics.com/diligent-engine/architecture/Vk/managing-resource-lifetimes/ - while (!m_VkObjReleaseQueue.empty()) { - auto &FirstObj = m_VkObjReleaseQueue.front(); - if (FirstObj.first <= CompletedFenceValue) - m_VkObjReleaseQueue.pop_front(); - else - break; + // This is OK if other thread disposes descriptor heap allocation at this time + // The allocation will be registered as part of the current frame + for(auto &Pool : m_DescriptorPools) + Pool.ReleaseStaleAllocations(CompletedFenceValue); } } diff --git a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp index c08e8c9d..31834c47 100644 --- a/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp +++ b/Graphics/GraphicsEngineVulkan/src/VulkanUtilities/VulkanDescriptorPool.cpp @@ -31,7 +31,7 @@ namespace VulkanUtilities { VulkanDescriptorPool::VulkanDescriptorPool(std::shared_ptr LogicalDevice, - const VkDescriptorPoolCreateInfo &DescriptorPoolCI) : + const VkDescriptorPoolCreateInfo &DescriptorPoolCI)noexcept : m_LogicalDevice(LogicalDevice) { VERIFY_EXPR(DescriptorPoolCI.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO); -- cgit v1.2.3