UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SkeletalMeshUpdater.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
8#include "Tasks/Task.h"
9#include "RHICommandList.h"
10
11class FRDGBuilder;
12class FRHICommandList;
14class FGPUSkinCache;
15class FSceneInterface;
20
21/*
22 The Skeletal Mesh Updater is an optimized pipeline for processing batches of skeletal mesh updates in parallel
23 with other scene rendering tasks. Each scene has an instance of this class. The system supports processing
24 commands from multiple channels, where each channel is a separate backend implementation. The resulting work
25 is processed in the same update tasks on the rendering timeline.
26
27 Frontend Usage:
28
29 Mesh objects are registered with the system on the game thread to receive a handle. The handle provides an interface to
30 push updates as well as release the instance:
31
32 FSkeletalMeshUpdater* Updater = Scene->GetSkeletalMeshUpdater();
33
34 // Creates a new handle associated with the object.
35 FSkeletalMeshUpdateHandle Handle = Updater->Create(MyMeshObject);
36
37 // Pushes a new update for the associated object.
38 Handle.Update(MyDynamicData);
39
40 // Releases the object from the updater.
41 Handle.Release();
42
43 Commands are automatically pushed by the system from the game thread to the render thread at sync points prior to rendering.
44 A delegate associated with UE::RenderCommandPipe::FSyncScope is used for this, as it already instruments key sync points.
45 Updates are not actually replayed until the next scene render, so an instance can very well receive multiple update requests
46 and then get removed. Removal is handled safely by releasing all pending updates and unregistering the instance. For multiple
47 updates, all intermediates must be processed back-to-back immediately and only the final update can get batched. This is to
48 simplify the batched path so that it does not have to handle multiple queued up states. In practice this scenario is rare and
49 is not on the performance critical path.
50
51 Backend Usage:
52
53 Updates are processed in stages based on the work that needs to be synced first in the pipeline. Mesh Deformer related work is synced
54 first, followed by skin cache, and finally inline skinning that touches mesh draw commands. A background task is kicked afterwards and this
55 is useful for performing RHI related updates; e.g. filling data into bone buffers or updating vertex factories, since that work does not
56 need to be synced until much later. Ideally only setup work is performed during the foreground stages.
57
58 Implementing a backend requires deriving from TSkeletalMeshUpdatePacket, which is associated with derived FSkeletalMeshObject / FSkeletalMeshDynamicData
59 types. As commands are replayed they are filtered into the user-derived TSkeletalMeshUpdatePacket class using template method overrides. Later the process
60 method associated with each stage is called in order. See the following example code for usage:
61
62 class FMyMeshObject : public FSkeletalMeshObject { ... };
63 class FMyMeshDynamicData : public FSkeletalMeshDynamicData { ... };
64
65 class FMySkeletalMeshUpdatePacket : public TSkeletalMeshUpdatePacket<FMyMeshObject, FMyMeshDynamicData>
66 {
67 public:
68 void Add(MeshObjectType* MeshObject, MeshDynamicDataType* MeshDynamicData)
69 {
70 // Filter the mesh object into the N stages of processing.
71 }
72
73 void UpdateImmediate(FRHICommandList& RHICmdList, MeshObjectType* MeshObject, MeshDynamicDataType* MeshDynamicData)
74 {
75 // Process this update immediately instead. This is how intermediate updates are handled if multiples get queued up.
76 }
77
78 void Process_SkinCache(FRHICommandList& RHICmdList)
79 {
80 // Do setup work associated with the skin cache (create buffers, register skin cache entries, etc).
81 }
82
83 void Process_Background(FRHICommandList& RHICmdList)
84 {
85 // Do update work for RHI resources that were allocated during setup.
86 }
87 }
88
89 // Registers the implementation and sets up a new channel in the updater.
90 REGISTER_SKELETAL_MESH_UPDATE_BACKEND(FMySkeletalMeshUpdatePacket);
91*/
92
94
96{
97public:
98 virtual ~FSkeletalMeshDynamicData() = default;
99
100private:
101 FSkeletalMeshDynamicData* Next = nullptr;
103
104 int32 PoolBucketIndex = 0;
105 int32 PoolBucketSize = 0;
106
107 template <typename DynamicDataType>
109};
110
112{
113public:
114 static int64 GetPoolBudget();
115
116protected:
117 static constexpr int32 NumPoolBuckets = 5;
118
119 int32 GetBucketIndex(int32 NumTransforms) const;
120
121#if COUNTERSTRACE_ENABLED
122 void AddStatsMemory(int32 BucketIndex, int32 Size);
123#endif
124};
125
126template <typename DynamicDataType>
128{
129public:
131 {
132 const int32 PoolBucketIndex = GetBucketIndex(NumTransforms);
133 DynamicDataType* DynamicData = GetBucket(PoolBucketIndex).Pop();
134
135 if (DynamicData)
136 {
137#if COUNTERSTRACE_ENABLED
138 AddStatsMemory(PoolBucketIndex, -DynamicData->PoolBucketSize);
139#endif
140 NumFreeBytes.fetch_sub(DynamicData->PoolBucketSize, std::memory_order_relaxed);
141 return DynamicData;
142 }
143
144 DynamicData = new DynamicDataType;
145 DynamicData->PoolBucketIndex = PoolBucketIndex;
146 return DynamicData;
147 }
148
149 void Release(DynamicDataType* DynamicData)
150 {
151 if (DynamicData)
152 {
153 const int32 DynamicDataSize = DynamicData->Reset();
154 DynamicData->PoolBucketSize = DynamicDataSize;
155 NumFreeBytes.fetch_add(DynamicDataSize, std::memory_order_relaxed);
156#if COUNTERSTRACE_ENABLED
157 AddStatsMemory(DynamicData->PoolBucketIndex, DynamicDataSize);
158#endif
159 GetBucket(DynamicData->PoolBucketIndex).Push(DynamicData);
160 }
161 }
162
163 void Trim()
164 {
165 int32 PoolBucketIndex = 0;
166
167 while (NumFreeBytes.load(std::memory_order_relaxed) > GetPoolBudget())
168 {
170
171 // Release more of the less detailed items relative to the high detailed ones to help balance the pools.
172 const int32 NumPoolBucketItems = NumPoolBuckets - PoolBucketIndex;
173
175 {
176 DynamicDataType* DynamicData = GetBucket(PoolBucketIndex).Pop();
177 if (!DynamicData)
178 {
179 break;
180 }
181 NumFreeItemBytes += DynamicData->PoolBucketSize;
182 delete DynamicData;
183 }
184
185 if (NumFreeItemBytes > 0)
186 {
187#if COUNTERSTRACE_ENABLED
188 AddStatsMemory(PoolBucketIndex, -NumFreeItemBytes);
189#endif
190 NumFreeBytes.fetch_sub(NumFreeItemBytes, std::memory_order_relaxed);
191 }
192
193 PoolBucketIndex = (PoolBucketIndex + 1) % NumPoolBuckets;
194 }
195 }
196
197private:
198 static TLockFreePointerListFIFO<DynamicDataType, 0>& GetBucket(int32 BucketIndex)
199 {
201 return Buckets[BucketIndex];
202 }
203
204 std::atomic<int64> NumFreeBytes = 0;
205};
206
207template <typename DynamicDataType>
209{
212
214
215public:
216 static void TrimPool()
217 {
218 Pool.Trim();
219 }
220
221 static DynamicDataType* Acquire(int32 LODIndex)
222 {
223 return Pool.Acquire(LODIndex);
224 }
225
226 static void Release(DynamicDataType* DynamicData)
227 {
228 Pool.Release(DynamicData);
229 }
230
231protected:
233 void Reset() {}
234};
235
236template <typename DynamicDataType>
238
240
242{
243 // Filtering of dynamic datas to mesh objects.
244 Filter,
245
246 // Processing inline mesh object allocations.
247 Inline,
248
249 // Processing mesh deformer mesh object allocations.
251
252 // Processing skin cache mesh object allocations.
254};
255
257{
258public:
266
267 virtual ~FSkeletalMeshUpdatePacket() = default;
268
270 // Virtual method overrides to process updates by stage. Each method is called in order, and each process stage is synced in order.
271
272 // Called before adding any skeletal mesh elements.
273 virtual void Init(const FInitializer& Initializer) {}
274
275 // Process all enqueued commands that must be synced prior to manipulating mesh deformers.
277
278 // Process all enqueued commands that must be synced prior to manipulating skin cache.
280
281 // Process all enqueued commands that must be synced prior to processing mesh draw commands.
283
284 // Process all enqueued commands that must be synced prior to completing the scene render.
286
288
290 {
291#if RHI_RAYTRACING
293#endif
294 }
295
297 {
298#if RHI_RAYTRACING
300#else
301 return false;
302#endif
303 }
304
305protected:
309
310private:
312 void Finalize();
313
314 virtual void TrimPool() = 0;
315
316#if RHI_RAYTRACING
318 bool bInvalidatePathTracedOutput = false;
319#endif
320
322};
323
324// The base class for implementing a new backend to the skeletal mesh updater.
325template <typename InMeshObjectType, typename InMeshDynamicDataType>
327{
328public:
331
333 // Template method overrides to filter update requests.
334
335 // Filter the update into a container to process by stage.
336 void Add(MeshObjectType* MeshObject, MeshDynamicDataType* MeshDynamicData) {}
337
338 // Process the update immediately. This is for intermediate updates if multiples get queued up between scene renders.
339 void UpdateImmediate(FRHICommandList& RHICmdList, MeshObjectType* MeshObject, MeshDynamicDataType* MeshDynamicData) {}
340
342
347};
348
350
351// Handle associated with a registered mesh object. It has move-only semantics. You must call Release() prior to destruction.
353{
354public:
356
358 : Channel(RHS.Channel)
359 , Index(RHS.Index)
360 {
361 RHS = {};
362 }
363
365 {
366 Channel = RHS.Channel;
367 Index = RHS.Index;
368 RHS.Channel = nullptr;
369 RHS.Index = INDEX_NONE;
370 return *this;
371 }
372
374 {
375 checkf(!Channel, TEXT("Call Release prior to destructing this handle"));
376 }
377
378 bool IsValid() const
379 {
380 return Channel != nullptr;
381 }
382
383 template <typename SkeletalMeshDynamicDataType>
384 [[nodiscard]] bool Update(SkeletalMeshDynamicDataType* MeshDynamicData);
385
386 void Release();
387
388private:
391
393};
394
396
398{
399public:
400 static bool IsEnabled();
401
403
405 // Game Thread Methods
406
407 // Call at creation time to register a new mesh object with the updater.
408 template <typename SkeletalMeshObjectType>
410
411 ENGINE_API void Shutdown();
412
414 {
416 check(!bInAsyncPushCommandsRegion);
417 bInAsyncPushCommandsRegion = true;
418 }
419
421 {
423 check(bInAsyncPushCommandsRegion);
424 bInAsyncPushCommandsRegion = false;
425 PushCommandsTask.Wait();
426 PushCommandsTask = {};
427 }
428
429 // Call to insert a task to push commands when the game thread task completes.
431
433 // Render Thread Methods
434
436 {
437 // These fire in order; e.g. syncing SkinCache syncs everything.
442 };
443
444 // Issues setup tasks to process commands pushed from the game side. Use the provided tasks to sync stages as needed. The builder automatically syncs otherwise.
445 ENGINE_API FSubmitTasks Submit(FRDGBuilder& GraphBuilder, ERHIPipeline GPUSkinCachePipeline);
446
447 // Waits for tasks associated with the provided update stage.
448 ENGINE_API static void WaitForStage(FRDGBuilder& GraphBuilder, ESkeletalMeshUpdateStage Stage);
449
451
452private:
453 struct FTaskData;
454
457 FDelegateHandle DelegateHandle;
459 UE::Tasks::FTask PushCommandsTask;
460 bool bSubmitting = false;
461 bool bInAsyncPushCommandsRegion = false;
462};
463
465
466// Macro to register a new backend using the derived packet type. This should only be used in a cpp file as it creates a statically initialized global.
467#define REGISTER_SKELETAL_MESH_UPDATE_BACKEND(SkeletalMeshUpdatePacketType) \
468 template <> \
469 struct FSkeletalMeshUpdateChannel::TLookupPacket<typename SkeletalMeshUpdatePacketType::MeshObjectType> \
470 { \
471 using Type = SkeletalMeshUpdatePacketType; \
472 }; \
473 template <> \
474 struct FSkeletalMeshUpdateChannel::TLookupPacket<typename SkeletalMeshUpdatePacketType::MeshDynamicDataType> \
475 { \
476 using Type = SkeletalMeshUpdatePacketType; \
477 }; \
478 FSkeletalMeshUpdateChannel::TBackend<SkeletalMeshUpdatePacketType> GSkeletalMeshUpdateChannelBackend_##SkeletalMeshUpdatePacketType;
479
481// Implementation only Classes
482
483// Class for pushing commands associated with a specific backend down the pipeline to be replayed into a packet.
485{
486 struct FIndexAllocator
487 {
488 void Free(int32 Index);
489 int32 Allocate();
490 int32 NumAllocated() const { return Max - FreeList.Num(); }
491
492 UE::FMutex Mutex;
493 TArray<int32> FreeList;
494 int32 Max = 0;
495 };
496
497 struct FOp : public TConcurrentLinearObject<FOp>
498 {
499 enum class EType : uint8
500 {
501 Add,
502 Update,
503 Remove
504 };
505
506 int32 HandleIndex;
507 EType Type;
508
509 union
510 {
511 struct
512 {
513 FSkeletalMeshDynamicData* MeshDynamicData;
514
515 } Data_Update;
516
517 struct
518 {
519 FSkeletalMeshObject* MeshObject;
520
521 } Data_Add;
522 };
523 };
524
525 struct FDynamicDataList
526 {
527 FSkeletalMeshDynamicData* Head = nullptr;
528 FSkeletalMeshDynamicData* Tail = nullptr;
529
530 void Add(FSkeletalMeshDynamicData* MeshDynamicData);
531
532 template <typename LambdaType>
533 void Consume(LambdaType&& Lambda);
534 };
535
536 struct FOpQueue
537 {
539 std::atomic_int32_t NumAdds = 0;
540 std::atomic_int32_t NumUpdates = 0;
541 std::atomic_int32_t NumRemoves = 0;
542 std::atomic_int32_t Num = 0;
543 };
544
545 struct FOpStream
546 {
548 int32 NumAdds = 0;
549 int32 NumRemoves = 0;
550 int32 NumUpdates = 0;
551 int32 Num = 0;
552 };
553
554 struct FSlot
555 {
556 FSkeletalMeshObject* MeshObject = nullptr;
557 FDynamicDataList UpdateList;
558 };
559
560 struct FSlotRegistry
561 {
562 TBitArray<> SlotBits;
563 TArray<FSlot> Slots;
564 };
565
566 struct FBackend : public TIntrusiveDoubleLinkedListNode<FBackend>
567 {
573
574 static FGlobalList& GetGlobalList();
575
576 ENGINE_API FBackend();
577 ENGINE_API virtual ~FBackend();
578
579 virtual TUniquePtr<FSkeletalMeshUpdatePacket> CreatePacket() const = 0;
580 virtual void Replay(FRHICommandList& RHICmdList, FSkeletalMeshUpdateChannel& Channel, FSkeletalMeshUpdatePacket& Packet) const = 0;
581
582 int32 GlobalListIndex = INDEX_NONE;
584 };
585
586 template <typename T>
587 struct TLookupPacket
588 {
589 static_assert(std::is_same<T, void>::value, "TLookupPacket: No specialization available for the given type!");
590 };
591
592public:
593 template <typename SkeletalMeshUpdatePacketType>
594 class TBackend final : private FBackend
595 {
596 public:
598 {
599 checkf(!Instance, TEXT("Multiple skeletal mesh update backends of the same type were instantiated. Only one is allowed at a time."));
600 Instance = this;
601 }
602
603 private:
604 static TBackend* Instance;
605
606 static int32 GetGlobalListIndex()
607 {
608 checkf(Instance, TEXT("Skeletal mesh backend instance was not instantiated."));
609 return Instance->GlobalListIndex;
610 }
611
612 static TBackend* GetInstance()
613 {
614 return Instance;
615 }
616
617 TUniquePtr<FSkeletalMeshUpdatePacket> CreatePacket() const override
618 {
620 }
621
622 void Replay(FRHICommandList& RHICmdList, FSkeletalMeshUpdateChannel& Channel, FSkeletalMeshUpdatePacket& Packet) const override
623 {
624 Channel.Replay(RHICmdList, static_cast<SkeletalMeshUpdatePacketType&>(Packet));
625 }
626
628 };
629
630 template <typename T>
632 {
633 return TBackend<typename TLookupPacket<T>::Type>::GetGlobalListIndex();
634 }
635
636 template <typename T>
637 bool IsChannelFor() const
638 {
639 return TBackend<typename TLookupPacket<T>::Type>::GetInstance() == Backend;
640 }
641
645
649
650private:
652 {
653 checkf(Backend, TEXT("Backend was released but the channel is still being used."));
654 return Backend->CreatePacket();
655 }
656
657 void Replay(FRHICommandList& RHICmdList, FSkeletalMeshUpdatePacket& Packet)
658 {
659 checkf(Backend, TEXT("Backend was released but the channel is still being used."));
660 Backend->Replay(RHICmdList, *this, Packet);
661 }
662
663 void Shutdown();
664
665 // Methods to push ops from the game thread queue to render thread op stream.
666 TUniquePtr<FOpQueue> PopFromQueue();
667 void PushToStream(TUniquePtr<FOpQueue>&& Ops);
668
669 template <typename SkeletalMeshUpdatePacketType>
670 void Replay(FRHICommandList& RHICmdList, SkeletalMeshUpdatePacketType& Packet);
671
672 FSkeletalMeshUpdatePacket::FInitializer GetPacketInitializer() const
673 {
675 {
676 .NumAdds = OpStream.NumAdds
677 , .NumRemoves = OpStream.NumRemoves
678 , .NumUpdates = OpStream.NumUpdates
679 };
680 }
681
682 FIndexAllocator IndexAllocator;
683 TUniquePtr<FOpQueue> OpQueue;
684 FOpStream OpStream;
685 FSlotRegistry SlotRegistry;
686 FBackend* Backend = nullptr;
687 int32 ChannelIndex;
688
690};
691
692template <typename SkeletalMeshUpdatePacketType>
694
696
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
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
void Init()
Definition LockFreeList.h:4
@ Num
Definition MetalRHIPrivate.h:234
ERHIPipeline
Definition RHIPipeline.h:13
ESkeletalMeshUpdateStage
Definition SkeletalMeshUpdater.h:242
CORE_API bool IsInGameThread()
Definition ThreadingBase.cpp:185
uint32 Size
Definition VulkanMemory.cpp:4034
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition IDelegateInstance.h:14
Definition GPUSkinCache.h:126
Definition RenderGraphBuilder.h:49
Definition RHICommandList.h:3819
Definition RenderingThread.h:831
Definition SceneInterface.h:106
Definition SkeletalMeshUpdater.h:112
int32 GetBucketIndex(int32 NumTransforms) const
Definition SkeletalMeshUpdater.cpp:37
static int64 GetPoolBudget()
Definition SkeletalMeshUpdater.cpp:30
static constexpr int32 NumPoolBuckets
Definition SkeletalMeshUpdater.h:117
Definition SkeletalMeshUpdater.h:96
virtual ~FSkeletalMeshDynamicData()=default
Definition SkeletalRenderPublic.h:85
Definition SkeletalMeshUpdater.h:595
TBackend()
Definition SkeletalMeshUpdater.h:597
Definition SkeletalMeshUpdater.h:485
static TArray< FSkeletalMeshUpdateChannel > GetChannels()
Definition SkeletalMeshUpdater.cpp:169
static int32 GetChannelIndex()
Definition SkeletalMeshUpdater.h:631
ENGINE_API ~FSkeletalMeshUpdateChannel()
Definition SkeletalMeshUpdater.cpp:196
bool IsChannelFor() const
Definition SkeletalMeshUpdater.h:637
Definition SkeletalMeshUpdater.h:353
~FSkeletalMeshUpdateHandle()
Definition SkeletalMeshUpdater.h:373
bool Update(SkeletalMeshDynamicDataType *MeshDynamicData)
void Release()
Definition SkeletalMeshUpdater.inl:16
bool IsValid() const
Definition SkeletalMeshUpdater.h:378
FSkeletalMeshUpdateHandle(FSkeletalMeshUpdateHandle &&RHS)
Definition SkeletalMeshUpdater.h:357
FSkeletalMeshUpdateHandle()=default
FSkeletalMeshUpdateHandle & operator=(FSkeletalMeshUpdateHandle &&RHS)
Definition SkeletalMeshUpdater.h:364
Definition SkeletalMeshUpdater.h:257
FSceneInterface * Scene
Definition SkeletalMeshUpdater.h:306
virtual ~FSkeletalMeshUpdatePacket()=default
ERHIPipeline GPUSkinCachePipeline
Definition SkeletalMeshUpdater.h:308
virtual void ProcessStage_Inline(FRHICommandList &, UE::Tasks::FTaskEvent &TaskEvent)
Definition SkeletalMeshUpdater.h:282
void InvalidatePathTracedOutput()
Definition SkeletalMeshUpdater.h:289
virtual void ProcessStage_SkinCache(FRHICommandList &, UE::Tasks::FTaskEvent &TaskEvent)
Definition SkeletalMeshUpdater.h:279
FGPUSkinCache * GPUSkinCache
Definition SkeletalMeshUpdater.h:307
virtual void ProcessStage_MeshDeformer(FRHICommandList &, UE::Tasks::FTaskEvent &TaskEvent)
Definition SkeletalMeshUpdater.h:276
virtual void Init(const FInitializer &Initializer)
Definition SkeletalMeshUpdater.h:273
virtual void ProcessStage_Upload(FRHICommandList &)
Definition SkeletalMeshUpdater.h:285
bool IsSkinCacheForRayTracingSupported() const
Definition SkeletalMeshUpdater.h:296
Definition SkeletalMeshUpdater.h:398
ENGINE_API FSubmitTasks Submit(FRDGBuilder &GraphBuilder, ERHIPipeline GPUSkinCachePipeline)
Definition SkeletalMeshUpdater.cpp:501
ENGINE_API void Shutdown()
Definition SkeletalMeshUpdater.cpp:347
static bool IsEnabled()
Definition SkeletalMeshUpdater.cpp:25
ENGINE_API UE::Tasks::FTask AddPushCommandsTask(const UE::Tasks::FTask &PrerequisiteTask)
Definition SkeletalMeshUpdater.cpp:357
void EndAsyncPushCommands()
Definition SkeletalMeshUpdater.h:420
void BeginAsyncPushCommands()
Definition SkeletalMeshUpdater.h:413
static ENGINE_API void WaitForStage(FRDGBuilder &GraphBuilder, ESkeletalMeshUpdateStage Stage)
Definition SkeletalMeshUpdater.cpp:561
Definition Array.h:670
Definition ClosableMpscQueue.h:17
Definition ConcurrentLinearAllocator.h:571
Definition IntrusiveDoubleLinkedList.h:25
Definition IntrusiveDoubleLinkedList.h:175
Definition LockFreeList.h:910
Definition SkeletalMeshUpdater.h:128
void Release(DynamicDataType *DynamicData)
Definition SkeletalMeshUpdater.h:149
void Trim()
Definition SkeletalMeshUpdater.h:163
DynamicDataType * Acquire(int32 NumTransforms)
Definition SkeletalMeshUpdater.h:130
Definition SkeletalMeshUpdater.h:209
TSkeletalMeshDynamicData()=default
static void TrimPool()
Definition SkeletalMeshUpdater.h:216
static DynamicDataType * Acquire(int32 LODIndex)
Definition SkeletalMeshUpdater.h:221
static void Release(DynamicDataType *DynamicData)
Definition SkeletalMeshUpdater.h:226
void Reset()
Definition SkeletalMeshUpdater.h:233
Definition SkeletalMeshUpdater.h:327
InMeshObjectType MeshObjectType
Definition SkeletalMeshUpdater.h:329
InMeshDynamicDataType MeshDynamicDataType
Definition SkeletalMeshUpdater.h:330
void UpdateImmediate(FRHICommandList &RHICmdList, MeshObjectType *MeshObject, MeshDynamicDataType *MeshDynamicData)
Definition SkeletalMeshUpdater.h:339
void TrimPool() override
Definition SkeletalMeshUpdater.h:343
void Add(MeshObjectType *MeshObject, MeshDynamicDataType *MeshDynamicData)
Definition SkeletalMeshUpdater.h:336
Definition StaticArray.h:26
Definition UniquePtr.h:107
Definition Mutex.h:18
Definition Task.h:236
bool Wait(FTimespan Timeout) const
Definition Task.h:76
U16 Index
Definition radfft.cpp:71
Definition SkeletalMeshUpdater.h:569
int32 Num
Definition SkeletalMeshUpdater.h:571
TIntrusiveDoubleLinkedList< FBackend > List
Definition SkeletalMeshUpdater.h:570
Definition SkeletalMeshUpdater.h:260
int32 NumAdds
Definition SkeletalMeshUpdater.h:261
ERHIPipeline SkinCachePipeline
Definition SkeletalMeshUpdater.h:264
int32 NumRemoves
Definition SkeletalMeshUpdater.h:262
int32 NumUpdates
Definition SkeletalMeshUpdater.h:263
Definition SkeletalMeshUpdater.h:436
UE::Tasks::FTask Inline
Definition SkeletalMeshUpdater.h:439
UE::Tasks::FTask Filter
Definition SkeletalMeshUpdater.h:438
UE::Tasks::FTask SkinCache
Definition SkeletalMeshUpdater.h:441
UE::Tasks::FTask MeshDeformer
Definition SkeletalMeshUpdater.h:440
Definition SkeletalMeshUpdater.cpp:396