Diligent Engine  v.2.4.g
DynamicHeap.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 Diligent Graphics LLC
3  * Copyright 2015-2019 Egor Yusov
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * In no event and under no legal theory, whether in tort (including negligence),
18  * contract, or otherwise, unless required by applicable law (such as deliberate
19  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
20  * liable for any damages, including any direct, indirect, special, incidental,
21  * or consequential damages of any character arising as a result of this License or
22  * out of the use or inability to use the software (including but not limited to damages
23  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
24  * all other commercial damages or losses), even if such Contributor has been advised
25  * of the possibility of such damages.
26  */
27 
28 #pragma once
29 
32 
33 #include <mutex>
34 #include <deque>
35 #include <vector>
36 #include <atomic>
38 #include "RingBuffer.hpp"
39 
40 namespace Diligent
41 {
42 
43 namespace DynamicHeap
44 {
45 
46 
47 // Having global ring buffer shared between all contexts is inconvinient because all contexts
48 // must share the same frame. Having individual ring bufer per context may result in a lot of unused
49 // memory. As a result, ring buffer is not currently used for dynamic memory management.
50 // Instead, every dynamic heap allocates pages from the global dynamic memory manager.
52 {
53 public:
57 
59  Uint32 Size) :
60  m_RingBuffer{Size, Allocator}
61  {}
62 
63  // clang-format off
68  // clang-format on
69 
70  void DiscardMasterBlocks(std::vector<MasterBlock>& /*Blocks*/, Uint64 FenceValue)
71  {
72  std::lock_guard<std::mutex> Lock{m_RingBufferMtx};
73  m_RingBuffer.FinishCurrentFrame(FenceValue);
74  }
75 
76  void ReleaseStaleBlocks(Uint64 LastCompletedFenceValue)
77  {
78  std::lock_guard<std::mutex> Lock{m_RingBufferMtx};
79  m_RingBuffer.ReleaseCompletedFrames(LastCompletedFenceValue);
80  }
81 
82  OffsetType GetSize() const { return m_RingBuffer.GetMaxSize(); }
83  OffsetType GetUsedSize() const { return m_RingBuffer.GetUsedSize(); }
84 
85 protected:
87  {
88  std::lock_guard<std::mutex> Lock{m_RingBufferMtx};
89  return m_RingBuffer.Allocate(SizeInBytes, Alignment);
90  }
91 
92 private:
93  std::mutex m_RingBufferMtx;
94  RingBuffer m_RingBuffer;
95 };
96 
97 
99 {
100 public:
103 
105  Uint32 Size) :
106  m_AllocationsMgr{Size, Allocator}
107  {
108 #ifdef DILIGENT_DEVELOPMENT
109  m_MasterBlockCounter = 0;
110 #endif
111  }
112 
113  // clang-format off
118  // clang-format on
119 
121  {
122  DEV_CHECK_ERR(m_MasterBlockCounter == 0, m_MasterBlockCounter, " master block(s) have not been returned to the manager");
123  }
124 
125  template <typename RenderDeviceImplType>
126  void ReleaseMasterBlocks(std::vector<MasterBlock>& Blocks, RenderDeviceImplType& Device, Uint64 CmdQueueMask)
127  {
128  struct StaleMasterBlock
129  {
130  MasterBlock Block;
132 
133  // clang-format off
134  StaleMasterBlock(MasterBlock&& _Block, MasterBlockListBasedManager* _Mgr)noexcept :
135  Block {std::move(_Block)},
136  Mgr {_Mgr }
137  {
138  }
139 
140  StaleMasterBlock (const StaleMasterBlock&) = delete;
141  StaleMasterBlock& operator= (const StaleMasterBlock&) = delete;
142  StaleMasterBlock& operator= ( StaleMasterBlock&&) = delete;
143 
144  StaleMasterBlock(StaleMasterBlock&& rhs)noexcept :
145  Block {std::move(rhs.Block)},
146  Mgr {rhs.Mgr }
147  {
148  rhs.Block = MasterBlock{};
149  rhs.Mgr = nullptr;
150  }
151  // clang-format on
152 
153  ~StaleMasterBlock()
154  {
155  if (Mgr != nullptr)
156  {
157  std::lock_guard<std::mutex> Lock{Mgr->m_AllocationsMgrMtx};
158 #ifdef DILIGENT_DEVELOPMENT
159  --Mgr->m_MasterBlockCounter;
160 #endif
161  Mgr->m_AllocationsMgr.Free(std::move(Block));
162  }
163  }
164  };
165  for (auto& Block : Blocks)
166  {
167  DEV_CHECK_ERR(Block.IsValid(), "Attempting to release invalid master block");
168  Device.SafeReleaseDeviceObject(StaleMasterBlock{std::move(Block), this}, CmdQueueMask);
169  }
170  }
171 
172  // clang-format off
173  OffsetType GetSize() const { return m_AllocationsMgr.GetMaxSize(); }
174  OffsetType GetUsedSize() const { return m_AllocationsMgr.GetUsedSize();}
175  // clang-format on
176 
177 #ifdef DILIGENT_DEVELOPMENT
178  int32_t GetMasterBlockCounter() const
179  {
180  return m_MasterBlockCounter;
181  }
182 #endif
183 
184 protected:
186  {
187  std::lock_guard<std::mutex> Lock{m_AllocationsMgrMtx};
188  auto NewBlock = m_AllocationsMgr.Allocate(SizeInBytes, Alignment);
189 #ifdef DILIGENT_DEVELOPMENT
190  if (NewBlock.IsValid())
191  {
192  ++m_MasterBlockCounter;
193  }
194 #endif
195  return NewBlock;
196  }
197 
198 private:
199  std::mutex m_AllocationsMgrMtx;
200  VariableSizeAllocationsManager m_AllocationsMgr;
201 
202 #ifdef DILIGENT_DEVELOPMENT
203  std::atomic_int32_t m_MasterBlockCounter;
204 #endif
205 };
206 
207 } // namespace DynamicHeap
208 
209 } // namespace Diligent
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::MasterBlockRingBufferBasedManager
MasterBlockRingBufferBasedManager(IMemoryAllocator &Allocator, Uint32 Size)
Definition: DynamicHeap.hpp:58
VariableSizeAllocationsManager.hpp
Diligent::RingBuffer
Implementation of a ring buffer. The class is not thread-safe.
Definition: RingBuffer.hpp:43
Diligent::RingBuffer::GetMaxSize
OffsetType GetMaxSize() const
Definition: RingBuffer.hpp:225
Diligent::RingBuffer::FinishCurrentFrame
void FinishCurrentFrame(Uint64 FenceValue)
Definition: RingBuffer.hpp:181
Diligent::VariableSizeAllocationsManager
Definition: VariableSizeAllocationsManager.hpp:64
Diligent::RingBuffer::ReleaseCompletedFrames
void ReleaseCompletedFrames(Uint64 CompletedFenceValue)
Definition: RingBuffer.hpp:197
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager
Definition: DynamicHeap.hpp:51
Diligent::DynamicHeap::MasterBlockListBasedManager::MasterBlockListBasedManager
MasterBlockListBasedManager(IMemoryAllocator &Allocator, Uint32 Size)
Definition: DynamicHeap.hpp:104
Diligent::VariableSizeAllocationsManager::GetMaxSize
OffsetType GetMaxSize() const
Definition: VariableSizeAllocationsManager.hpp:357
Diligent::Uint64
uint64_t Uint64
64-bit unsigned integer
Definition: BasicTypes.h:50
Diligent::DynamicHeap::MasterBlockListBasedManager::~MasterBlockListBasedManager
~MasterBlockListBasedManager()
Definition: DynamicHeap.hpp:120
Diligent::VariableSizeAllocationsManager::Allocation
Definition: VariableSizeAllocationsManager.hpp:156
Diligent::DynamicHeap::MasterBlockListBasedManager::AllocateMasterBlock
MasterBlock AllocateMasterBlock(OffsetType SizeInBytes, OffsetType Alignment)
Definition: DynamicHeap.hpp:185
Diligent::DynamicHeap::MasterBlockListBasedManager::GetSize
OffsetType GetSize() const
Definition: DynamicHeap.hpp:173
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::DiscardMasterBlocks
void DiscardMasterBlocks(std::vector< MasterBlock > &, Uint64 FenceValue)
Definition: DynamicHeap.hpp:70
Diligent::DynamicHeap::MasterBlockListBasedManager::GetUsedSize
OffsetType GetUsedSize() const
Definition: DynamicHeap.hpp:174
Diligent::VariableSizeAllocationsManager::GetUsedSize
OffsetType GetUsedSize() const
Definition: VariableSizeAllocationsManager.hpp:359
DEV_CHECK_ERR
#define DEV_CHECK_ERR(...)
Definition: DebugUtilities.hpp:90
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::InvalidOffset
static constexpr const OffsetType InvalidOffset
Definition: DynamicHeap.hpp:56
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::OffsetType
RingBuffer::OffsetType OffsetType
Definition: DynamicHeap.hpp:54
Diligent::RingBuffer::Allocate
OffsetType Allocate(OffsetType Size, OffsetType Alignment)
Definition: RingBuffer.hpp:115
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::GetUsedSize
OffsetType GetUsedSize() const
Definition: DynamicHeap.hpp:83
Diligent::VariableSizeAllocationsManager::Allocate
Allocation Allocate(OffsetType Size, OffsetType Alignment)
Definition: VariableSizeAllocationsManager.hpp:188
Diligent::RingBuffer::InvalidOffset
static constexpr const OffsetType InvalidOffset
Definition: RingBuffer.hpp:63
Diligent::RingBuffer::GetUsedSize
OffsetType GetUsedSize() const
Definition: RingBuffer.hpp:228
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::operator=
MasterBlockRingBufferBasedManager & operator=(const MasterBlockRingBufferBasedManager &)=delete
RingBuffer.hpp
Diligent::VariableSizeAllocationsManager::OffsetType
size_t OffsetType
Definition: VariableSizeAllocationsManager.hpp:67
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::ReleaseStaleBlocks
void ReleaseStaleBlocks(Uint64 LastCompletedFenceValue)
Definition: DynamicHeap.hpp:76
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:51
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::MasterBlock
RingBuffer::OffsetType MasterBlock
Definition: DynamicHeap.hpp:55
Diligent::RingBuffer::OffsetType
size_t OffsetType
Definition: RingBuffer.hpp:46
Diligent::IMemoryAllocator
Base interface for a raw memory allocator.
Definition: MemoryAllocator.h:41
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::GetSize
OffsetType GetSize() const
Definition: DynamicHeap.hpp:82
Diligent::DynamicHeap::MasterBlockListBasedManager::ReleaseMasterBlocks
void ReleaseMasterBlocks(std::vector< MasterBlock > &Blocks, RenderDeviceImplType &Device, Uint64 CmdQueueMask)
Definition: DynamicHeap.hpp:126
Diligent::DynamicHeap::MasterBlockListBasedManager::operator=
MasterBlockListBasedManager & operator=(const MasterBlockListBasedManager &)=delete
Diligent::DynamicHeap::MasterBlockRingBufferBasedManager::AllocateMasterBlock
MasterBlock AllocateMasterBlock(OffsetType SizeInBytes, OffsetType Alignment)
Definition: DynamicHeap.hpp:86
Diligent::DynamicHeap::MasterBlockListBasedManager
Definition: DynamicHeap.hpp:98
Diligent::DynamicHeap::MasterBlockListBasedManager::OffsetType
VariableSizeAllocationsManager::OffsetType OffsetType
Definition: DynamicHeap.hpp:101
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37
Diligent::VariableSizeAllocationsManager::Free
void Free(Allocation &&allocation)
Definition: VariableSizeAllocationsManager.hpp:251