UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ResourcePool.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 Resource.h: Template for pooling resources using buckets.
5 =============================================================================*/
6
7#pragma once
8
9#include "CoreMinimal.h"
10#include "RenderResource.h"
12#include "RHICommandList.h"
13#include "Async/Mutex.h"
14
16template<typename ResourceType, class ResourcePoolPolicy, class ResourceCreationArguments>
18{
19public:
20 TResourcePool() = default;
21
28
31 {
32 DrainPool(true);
33 }
34
40 {
41 const uint32 BucketIndex = Policy.GetPoolBucketIndex(Args);
42 return Policy.GetPoolBucketSize(BucketIndex);
43 }
44
50 {
51 // Find the appropriate bucket based on size
52 const uint32 BucketIndex = Policy.GetPoolBucketIndex(Args);
53 TArray<FPooledResource>& PoolBucket = ResourceBuckets[BucketIndex];
54
55 {
56 UE::TConditionalScopeLock Lock(CS, !bLocked);
57
58 if (PoolBucket.Num() > 0)
59 {
60 // Reuse the last entry in this size bucket
61 return PoolBucket.Pop(EAllowShrinking::No).Resource;
62 }
63 }
64
65 // Nothing usable was found in the free pool, create a new resource
66 return Policy.CreateResource(RHICmdList, Args);
67 }
68
72 void ReleasePooledResource(ResourceType&& Resource)
73 {
74 FPooledResource NewEntry;
75 NewEntry.CreationArguments = Policy.GetCreationArguments(Resource);
76 NewEntry.Resource = Forward<ResourceType&&>(Resource);
77 NewEntry.FrameFreed = GFrameNumberRenderThread;
78 NewEntry.BucketIndex = Policy.GetPoolBucketIndex(NewEntry.CreationArguments);
79
80 // Add to this frame's array of free resources
81 const int32 SafeFrameIndex = GFrameNumberRenderThread % ResourcePoolPolicy::NumSafeFrames;
82
83 UE::TConditionalScopeLock Lock(CS, !bLocked);
84 SafeResourceBuckets[SafeFrameIndex].Emplace(MoveTemp(NewEntry));
85 }
86
91 {
92 uint32 NumToCleanThisFrame = ResourcePoolPolicy::NumToDrainPerFrame;
93 uint32 CullAfterFramesNum = ResourcePoolPolicy::CullAfterFramesNum;
94
95 check(!bLocked);
97
99 {
100 // DrainPool won't necessarily be called at the same frequency as the render thread number increments.
101 // Therefore, we track the frame number from the previous drain that occurred and drain all frames between
102 // the last and the current frame number (capping out at draining all frames).
103
105
106 if (LastSafeFrameNumber == INDEX_NONE)
107 {
108 LastSafeFrameNumber = SafeFrameNumber;
109 }
110
111 uint32 NumSafeFramesToDrain = FMath::Clamp<uint32>(SafeFrameNumber - LastSafeFrameNumber, 1, ResourcePoolPolicy::NumSafeFrames);
112
114 {
115 // Index of the bucket that is now old enough to be reused
116 const int32 SafeFrameIndex = (LastSafeFrameNumber + Index) % ResourcePoolPolicy::NumSafeFrames;
117
118 for (FPooledResource& PoolEntry : SafeResourceBuckets[SafeFrameIndex])
119 {
120 ResourceBuckets[PoolEntry.BucketIndex].Emplace(MoveTemp(PoolEntry));
121 }
122 SafeResourceBuckets[SafeFrameIndex].Reset();
123 }
124
125 LastSafeFrameNumber = SafeFrameNumber;
126 }
127 else
128 {
129 for (int32 FrameIndex = 0; FrameIndex < ResourcePoolPolicy::NumSafeFrames; FrameIndex++)
130 {
131 for (FPooledResource& PoolEntry : SafeResourceBuckets[FrameIndex])
132 {
133 ResourceBuckets[PoolEntry.BucketIndex].Emplace(MoveTemp(PoolEntry));
134 }
135 SafeResourceBuckets[FrameIndex].Reset();
136 }
137 }
138
139 // Clean a limited number of old entries to reduce hitching when leaving a large level
140 for (int32 BucketIndex = 0; BucketIndex < ResourcePoolPolicy::NumPoolBuckets; BucketIndex++)
141 {
142 for (int32 EntryIndex = ResourceBuckets[BucketIndex].Num() - 1; EntryIndex >= 0; EntryIndex--)
143 {
144 FPooledResource& PoolEntry = ResourceBuckets[BucketIndex][EntryIndex];
145
146 // Clean entries that are unlikely to be reused
147 if ((GFrameNumberRenderThread - PoolEntry.FrameFreed) > CullAfterFramesNum || bForceDrainAll)
148 {
149 Policy.FreeResource(ResourceBuckets[BucketIndex][EntryIndex].Resource);
150
151 ResourceBuckets[BucketIndex].RemoveAtSwap(EntryIndex, EAllowShrinking::No);
152
155 {
156 break;
157 }
158 }
159 }
160
162 {
163 break;
164 }
165 }
166 }
167
170 {
171 public:
173 : Pool(InPool)
174 , Lock(Pool.CS)
175 {
176 check(!Pool.bLocked);
177 Pool.bLocked = true;
178 }
179
181 {
182 Pool.bLocked = false;
183 }
184
185 private:
186 TResourcePool& Pool;
188 };
189
190private:
192 ResourcePoolPolicy Policy;
193
194 // Describes a Resource in the free pool.
195 struct FPooledResource
196 {
198 ResourceType Resource;
200 ResourceCreationArguments CreationArguments;
202 uint32 FrameFreed;
203 uint32 BucketIndex;
204 };
205
206 uint32 LastSafeFrameNumber = INDEX_NONE;
207 UE::FMutex CS;
208 bool bLocked = false;
209
210 // Pool of free Resources, indexed by bucket for constant size search time.
211 TArray<FPooledResource> ResourceBuckets[ResourcePoolPolicy::NumPoolBuckets];
212
213 // Resources that have been freed more recently than NumSafeFrames ago.
214 TArray<FPooledResource> SafeResourceBuckets[ResourcePoolPolicy::NumSafeFrames];
215};
216
218template<typename ResourceType, class ResourcePoolPolicy, class ResourceCreationArguments>
219class TRenderResourcePool : public TResourcePool<ResourceType, ResourcePoolPolicy, ResourceCreationArguments>, public FTickableObjectRenderThread, public FRenderResource
220{
221public:
227
236
239 {
240 }
241
247 {
248 if (IsInitialized())
249 {
251 }
252 else
253 {
254 return ResourceType();
255 }
256 }
257
258 UE_DEPRECATED(5.4, "CreatePooledResource requires an RHI command list.")
260 {
261 if (IsInitialized())
262 {
264 }
265 else
266 {
267 return ResourceType();
268 }
269 }
270
281
282public: // From FTickableObjectRenderThread
283 virtual void Tick(FRHICommandListImmediate& RHICmdList, float DeltaTime ) override
284 {
286
288 }
289
290 virtual bool IsTickable() const override
291 {
292 return true;
293 }
294
296 {
297 return true;
298 }
299
300public: // From FRenderResource
301 virtual void InitRHI(FRHICommandListBase& RHICmdList) override
302 {
304 }
305
311};
#define check(expr)
Definition AssertionMacros.h:314
#define ensure( InExpression)
Definition AssertionMacros.h:464
uint32 GFrameNumberRenderThread
Definition CoreGlobals.cpp:427
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
@ Num
Definition MetalRHIPrivate.h:234
CORE_API bool IsInRenderingThread()
Definition ThreadingBase.cpp:273
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
FRWLock Lock
Definition UnversionedPropertySerialization.cpp:921
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition RHICommandList.h:455
Definition RHICommandList.h:4626
static FRHICommandListImmediate & Get()
Definition RHICommandList.h:5522
Definition RenderResource.h:37
bool IsInitialized() const
Definition RenderResource.h:114
Definition TickableObjectRenderThread.h:15
void Unregister()
Definition TickableObjectRenderThread.h:61
void Register()
Definition TickableObjectRenderThread.h:79
Definition Array.h:670
void Reset(SizeType NewSize=0)
Definition Array.h:2246
UE_FORCEINLINE_HINT void RemoveAtSwap(SizeType Index, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2185
UE_FORCEINLINE_HINT SizeType Emplace(ArgsType &&... Args)
Definition Array.h:2561
Definition ResourcePool.h:220
virtual bool NeedsRenderingResumedForRenderingThreadTick() const override
Definition ResourcePool.h:295
virtual void Tick(FRHICommandListImmediate &RHICmdList, float DeltaTime) override
Definition ResourcePool.h:283
virtual void ReleaseRHI() override
Definition ResourcePool.h:306
void ReleasePooledResource(ResourceType &&Resource)
Definition ResourcePool.h:274
virtual void InitRHI(FRHICommandListBase &RHICmdList) override
Definition ResourcePool.h:301
virtual bool IsTickable() const override
Definition ResourcePool.h:290
TRenderResourcePool(ResourcePoolPolicy InPolicy)
Definition ResourcePool.h:231
TRenderResourcePool()
Definition ResourcePool.h:223
virtual ~TRenderResourcePool()
Definition ResourcePool.h:238
ResourceType CreatePooledResource(FRHICommandListBase &RHICmdList, ResourceCreationArguments Args)
Definition ResourcePool.h:246
Definition ResourcePool.h:170
FLockScope(TResourcePool &InPool)
Definition ResourcePool.h:172
~FLockScope()
Definition ResourcePool.h:180
Definition ResourcePool.h:18
virtual ~TResourcePool()
Definition ResourcePool.h:30
void ReleasePooledResource(ResourceType &&Resource)
Definition ResourcePool.h:72
TResourcePool(ResourcePoolPolicy InPolicy)
Definition ResourcePool.h:25
uint32 PooledSizeForCreationArguments(ResourceCreationArguments Args)
Definition ResourcePool.h:39
ResourceType CreatePooledResource(FRHICommandListBase &RHICmdList, ResourceCreationArguments Args)
Definition ResourcePool.h:49
void DrainPool(bool bForceDrainAll)
Definition ResourcePool.h:90
TResourcePool()=default
Definition Mutex.h:18
Definition ScopeLock.h:53
Definition ScopeLock.h:21
@ false
Definition radaudio_common.h:23
U16 Index
Definition radfft.cpp:71