UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
RenderingThread.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 RenderingThread.h: Rendering thread definitions.
5=============================================================================*/
6
7#pragma once
8
10#include "Containers/Array.h"
11#include "Containers/List.h"
12#include "CoreGlobals.h"
13#include "CoreMinimal.h"
14#include "CoreTypes.h"
15#include "Delegates/Delegate.h"
16#include "HAL/PlatformMemory.h"
18#include "Misc/TVariant.h"
19#include "MultiGPU.h"
21#include "RHI.h"
22#include "RHICommandList.h"
24#include "Stats/Stats.h"
25#include "Templates/Atomic.h"
26#include "Templates/Function.h"
29#include "Trace/Trace.h"
30#include "Async/Mutex.h"
31#include "Tasks/Pipe.h"
32
33#define UE_API RENDERCORE_API
34
35namespace UE { namespace Trace { class FChannel; } }
36
37enum class EParallelForFlags;
38
40// Render thread API
42
43namespace FFrameEndSync
44{
45 enum class EFlushMode
46 {
47 // Blocks the caller until the N - m frame has completed, where m is driven by various config.
49
50 // Blocks the caller until all rendering work is completed on the CPU. Does not sync with the GPU.
52 };
53
54 // Syncs the game thread based on progress throughout the rendering pipeline.
56};
57
63
69
70// Global for handling the "togglerenderthread" command.
72
73#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
74 inline void CheckNotBlockedOnRenderThread() {}
75#else // #if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
77 extern RENDERCORE_API TAtomic<bool> GMainThreadBlockedOnRenderThread;
78
81#endif // #if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
82
83
84// Called during engine init to setup the rendering thread.
86
87// Called during engine shutdown to stop the rendering thread.
89
90// Called once per frame by the game thread to latch the latest render thread config.
92
98
101
106
111
112UE_DEPRECATED(5.6, "FlushPendingDeleteRHIResources_GameThread is deprecated. Enqueue a render command that calls ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources) on the immediate RHI command list instead.")
114UE_DEPRECATED(5.6, "FlushPendingDeleteRHIResources_RenderThread is deprecated. Call ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources) on the immediate RHI command list instead.")
116
119
129
131// Render commands
133
135
136//
137// Macros for using render commands.
138//
139// ideally this would be inline, however that changes the module dependency situation
141
143
144// Log render commands on server for debugging
145#if 0 // UE_SERVER && UE_BUILD_DEBUG
146 #define LogRenderCommand(TypeName) UE_LOG(LogRHI, Warning, TEXT("Render command '%s' is being executed on a dedicated server."), TEXT(#TypeName))
147#else
148 #define LogRenderCommand(TypeName)
149#endif
150
151// conditions when rendering commands are executed in the thread
152#if UE_SERVER
153 #define ShouldExecuteOnRenderThread() false
154#else
155 #define ShouldExecuteOnRenderThread() (LIKELY(GIsThreadedRendering || !IsInGameThread()))
156#endif // UE_SERVER
157
159{
160public:
161 const TCHAR* GetName() const
162 {
163 return Name;
164 }
165
167 {
168 return StatId;
169 }
170
172 {
173 return SpecId;
174 }
175
176protected:
178 : Name(InName)
179 , StatId(InStatId)
180 {}
181
182private:
183 const TCHAR* Name;
184 TStatId StatId;
185 mutable uint32 SpecId;
186};
187
189template <typename TSTR>
191{
192public:
193 static const TRenderCommandTag& Get()
194 {
195#if STATS
196 struct FStatData
197 {
199 static inline const char* GetStatName()
200 {
201 return TSTR::CStr();
202 }
203 static inline const TCHAR* GetDescription()
204 {
205 return TSTR::TStr();
206 }
207 static inline EStatDataType::Type GetStatType()
208 {
209 return EStatDataType::ST_int64;
210 }
211 static inline bool IsClearEveryFrame()
212 {
213 return true;
214 }
215 static inline bool IsCycleStat()
216 {
217 return true;
218 }
220 {
222 }
223 };
225 static TRenderCommandTag Tag(TSTR::TStr(), Stat.GetStatId());
226#else
227 static TRenderCommandTag Tag(TSTR::TStr(), TStatId());
228#endif
229
230 return Tag;
231 }
232
233private:
235 : FRenderCommandTag(InName, InStatId)
236 {}
237};
238
240#define DECLARE_RENDER_COMMAND_TAG(Type, Name) \
241 struct PREPROCESSOR_JOIN(TSTR_, PREPROCESSOR_JOIN(Name, __LINE__)) \
242 { \
243 static const char* CStr() { return #Name; } \
244 static const TCHAR* TStr() { return TEXT(#Name); } \
245 }; \
246 using Type = TRenderCommandTag<PREPROCESSOR_JOIN(TSTR_, PREPROCESSOR_JOIN(Name, __LINE__))>;
247
250{
252 None,
253
256
258 All
259};
260
262{
263 None = 0,
264
266 Disabled = 1 << 0
267};
268
270
275
280>;
281
282namespace UE::RenderCommandPipe
283{
284 // [Game Thread] Initializes all statically initialized render command pipes.
285 extern RENDERCORE_API void Initialize();
286
287 // [Game Thread (Parallel)] Returns whether any render command pipes are currently recording on the game thread timeline.
288 extern RENDERCORE_API bool IsRecording();
289
290 // [Render Thread (Parallel)] Returns whether any render command pipes are currently replaying commands on the render thread timeline.
291 extern RENDERCORE_API bool IsReplaying();
292
293 // [Render Thread (Parallel)] Returns whether the specific render command pipe is replaying.
294 extern RENDERCORE_API bool IsReplaying(const FRenderCommandPipe& Pipe);
295
296 // [Game Thread] Starts recording render commands into pipes. Returns whether the operation succeeded.
297 extern RENDERCORE_API void StartRecording();
298 extern RENDERCORE_API void StartRecording(const FRenderCommandPipeBitArray& PipeBits);
299
300 // [Game Thread] Stops recording commands into pipes and syncs all remaining pipe work to the render thread. Returns whether the operation succeeded.
301 extern RENDERCORE_API FRenderCommandPipeBitArray StopRecording();
303
304 // Returns the list of all registered pipes.
306
307 // A delegate to receive events at sync points when recording is stopped. Input is a bit array of pipes that were stopped.
309 extern RENDERCORE_API FStopRecordingDelegate& GetStopRecordingDelegate();
310
311 // [Game Thread] Stops render command pipe recording during the duration of the scope and restarts recording once the scope is complete.
313 {
314 public:
318
319 private:
321 };
322
323 // Utility class containing a simple linked list of render commands.
325 {
326 enum class ECommandType : uint8
327 {
328 ExecuteFunction,
329 ExecuteCommandList
330 };
331
332 struct FCommand
333 {
334 virtual ~FCommand() = default;
335
336 FCommand(ECommandType InType)
337 : Type(InType)
338 {}
339
340 FCommand* Next = nullptr;
341 ECommandType Type;
342 };
343
344 struct FExecuteFunctionCommand
345 : public FCommand
347 {
348 FExecuteFunctionCommand(FRenderCommandFunctionVariant&& InFunction, const FRenderCommandTag& InTag)
349 : FCommand(ECommandType::ExecuteFunction)
350 , Tag(InTag)
352 {
354 }
355
356 const FRenderCommandTag& Tag;
358 };
359
360 struct FExecuteCommandListCommand : public FCommand
361 {
362 FExecuteCommandListCommand(FCommandList* InCommandList)
363 : FCommand(ECommandType::ExecuteCommandList)
364 , CommandList(InCommandList)
365 {}
366
367 FCommandList* CommandList;
368 };
369
370 public:
374
375 // Assigns the allocator reference and then moves the command list and its allocator contents into this one.
377 : Allocator(InAllocator)
378 {
379 Allocator = MoveTemp(CommandListToConsume.Allocator);
380 Commands = CommandListToConsume.Commands;
381 CommandListToConsume.Commands = {};
382
383#if DO_CHECK
384 bClosed = CommandListToConsume.bClosed;
385 CommandListToConsume.bClosed = false;
386#endif
387 }
388
390 {
391 Release();
392 }
393
394 template <typename RenderCommandTag, typename FunctionType>
399
400 template <typename RenderCommandTag>
402 {
403 return Enqueue(MoveTemp(Function), RenderCommandTag::Get());
404 }
405
407
408 RENDERCORE_API bool Enqueue(FCommandList* CommandList);
409
410 void Close()
411 {
412#if DO_CHECK
413 bClosed = true;
414#endif
415 }
416
417 template <typename LambdaType>
418 void ConsumeCommands(const LambdaType& Lambda)
419 {
420#if DO_CHECK
421 check(bClosed);
422#endif
423
424 for (FCommand* Command = Commands.Head; Command; Command = Command->Next)
425 {
426 if (Command->Type == ECommandType::ExecuteFunction)
427 {
428 FExecuteFunctionCommand* FunctionCommand = static_cast<FExecuteFunctionCommand*>(Command);
430 Lambda(MoveTemp(FunctionCommand->Function), FunctionCommand->Tag);
431 FunctionCommand->~FExecuteFunctionCommand();
432 }
433 else
434 {
435 check(Command->Type == ECommandType::ExecuteCommandList);
436 FExecuteCommandListCommand* CommandListCommand = static_cast<FExecuteCommandListCommand*>(Command);
437 CommandListCommand->CommandList->ConsumeCommands(Lambda);
438 CommandListCommand->~FExecuteCommandListCommand();
439 }
440 }
441 Commands = {};
442#if DO_CHECK
443 bClosed = false;
444#endif
445 }
446
447 inline int32 NumCommands() const
448 {
449 return Commands.Num;
450 }
451
452 inline bool IsEmpty() const
453 {
454 return !Commands.Head;
455 }
456
457 private:
458 RENDERCORE_API bool Enqueue(FCommand* Command);
459
460 template <typename T, typename... TArgs>
461 inline T* AllocNoDestruct(TArgs&&... Args)
462 {
463 return new (Allocator) T(Forward<TArgs&&>(Args)...);
464 }
465
466 RENDERCORE_API void Release();
467
468 FMemStackBase& Allocator;
469
470 struct
471 {
472 FCommand* Head = nullptr;
473 FCommand* Tail = nullptr;
475
476 } Commands;
477
478#if DO_CHECK
479 bool bClosed = false;
480#endif
481 };
482}
483
485
487
489{
490public:
492 {
493 delete Context;
494 }
495
496protected:
498 {
499 // If the context's command list is not empty then a task must have been launched that will consume its contents.
500 // Replace the context with a new one and mark the old one for deletion. Any new commands issued into the new context
501 // will issue a new task scheduled after this command list executes.
502
504 {
506 Context = new FContext();
507 }
508 }
509
526
529};
530
532{
533 RENDERCORE_API static void ExecuteCommands(FRenderCommandList* CommandList);
534 RENDERCORE_API static void ExecuteCommands(UE::RenderCommandPipe::FCommandList& CommandList);
535
536 class FRenderCommandTaskBase
537 {
538 public:
539 static ENamedThreads::Type GetDesiredThread()
540 {
543 }
544
545 static ESubsequentsMode::Type GetSubsequentsMode()
546 {
548 }
549 };
550
551 template <typename LambdaType>
552 class TRenderCommandTask : public FRenderCommandTaskBase
553 {
554 public:
555 TRenderCommandTask(LambdaType&& InLambda, const FRenderCommandTag& InTag)
556 : Tag(InTag)
558 {}
559
560 void DoTask(ENamedThreads::Type, const FGraphEventRef&)
561 {
564 }
565
566 inline TStatId GetStatId() const
567 {
568 return Tag.GetStatId();
569 }
570
571 private:
572 const FRenderCommandTag& Tag;
573 LambdaType Lambda;
574 };
575
576 class FRenderCommandListTask : public FRenderCommandTaskBase
577 {
578 public:
579 FRenderCommandListTask(FRenderCommandList* InCommandList)
580 : CommandList(InCommandList)
581 {}
582
583 void DoTask(ENamedThreads::Type, const FGraphEventRef&)
584 {
585 FRenderThreadCommandPipe::ExecuteCommands(CommandList);
586 }
587
588 private:
589 FRenderCommandList* CommandList;
590 };
591
592public:
593 template <typename RenderCommandTag, typename LambdaType>
594 static void Enqueue(LambdaType&& Lambda)
595 {
596 const FRenderCommandTag& Tag = RenderCommandTag::Get();
598
600 {
602
604 {
605 Instance.EnqueueAndLaunch(MoveTemp(Lambda), Tag);
606 }
607 else
608 {
609 TGraphTask<TRenderCommandTask<LambdaType>>::CreateTask().ConstructAndDispatchWhenReady(MoveTemp(Lambda), Tag);
610 }
611 }
612 else
613 {
614 FScopeCycleCounter CycleScope(Tag.GetStatId());
616 }
617 }
618
619 static void Enqueue(FRenderCommandList* CommandList)
620 {
621 if (CommandList)
622 {
624 {
626
628 {
629 Instance.EnqueueAndLaunch(CommandList);
630 }
631 else
632 {
634 }
635 }
636 else
637 {
638 ExecuteCommands(CommandList);
639 }
640 }
641 }
642
643private:
645
646 RENDERCORE_API void EnqueueAndLaunch(FRenderCommandList* CommandList);
649};
650
652{
653public:
656
658
659 inline const TCHAR* GetName() const
660 {
661 return Name;
662 }
663
664 inline bool IsValid() const
665 {
666 return Index != INDEX_NONE;
667 }
668
669 inline int32 GetIndex() const
670 {
671 check(IsValid());
672 return Index;
673 }
674
675 inline bool IsReplaying() const
676 {
678 return bReplaying;
679 }
680
681 inline bool IsRecording() const
682 {
683 return bRecording;
684 }
685
686 inline bool IsEmpty() const
687 {
688 return NumInFlightCommands.load(std::memory_order_relaxed) == 0 && NumInFlightCommandLists.load(std::memory_order_relaxed) == 0;
689 }
690
692 {
694 bEnabled = bInIsEnabled;
695 }
696
698
700 {
702 {
704
705 checkf(!UE::RenderCommandPipe::IsReplaying(*this), TEXT("Enqueuing command queues from the render command pipe replay task is not allowed."));
706
707 if (RecordTask.IsValid())
708 {
709 EnqueueAndLaunch(RenderCommandList);
710 return true;
711 }
712 }
713 return false;
714 }
715
716 template <typename RenderCommandTag>
718 {
719 // Execute the function directly if this is being called recursively from within another pipe command.
720 if (UE::RenderCommandPipe::IsReplaying(*this))
721 {
722 ExecuteCommand(MoveTemp(Function), RenderCommandTag::Get());
723 return true;
724 }
725
727
728 if (RecordTask.IsValid())
729 {
730 EnqueueAndLaunch(MoveTemp(Function), RenderCommandTag::Get());
731 return true;
732 }
733
734 return false;
735 }
736
737 template <typename RenderCommandTag>
739 {
740 // Execute the function directly if this is being called recursively from within another pipe command.
741 if (UE::RenderCommandPipe::IsReplaying(*this))
742 {
743 ExecuteCommand(MoveTemp(Function), RenderCommandTag::Get());
744 return true;
745 }
746
748
749 if (RecordTask.IsValid())
750 {
751 EnqueueAndLaunch(MoveTemp(Function), RenderCommandTag::Get());
752 return true;
753 }
754
755 return false;
756 }
757
759
760private:
763
764 RENDERCORE_API void EnqueueAndLaunch(FRenderCommandList* CommandList);
766
767 void EnqueueAndLaunch(FCommandListFunction&& Function, const FRenderCommandTag& Tag)
768 {
770 }
771
772 void EnqueueAndLaunch(FEmptyFunction&& Function, const FRenderCommandTag& Tag)
773 {
775 }
776
778
779 void ExecuteCommand(FCommandListFunction&& Function, const FRenderCommandTag& Tag)
780 {
782 }
783
784 void ExecuteCommand(FEmptyFunction&& Function, const FRenderCommandTag& Tag)
785 {
787 }
788
789 void ExecuteCommands(UE::RenderCommandPipe::FCommandList& CommandList);
790 void ExecuteCommands(FRenderCommandList* CommandList);
791
792 const TCHAR* Name;
793 UE::Tasks::FTask RecordTask;
794 FRHICommandList* RHICmdList = nullptr;
796 FAutoConsoleVariable ConsoleVariable;
797 std::atomic_int32_t NumInFlightCommands{ 0 };
798 std::atomic_int32_t NumInFlightCommandLists{ 0 };
800 bool bRecording = false;
801 bool bReplaying = false;
802 bool bEnabled = true;
803};
804
806{
807 None,
808
809 // Closes the command list on a call to Submit. Enables an optimization to skip submitting empty lists.
810 CloseOnSubmit = 1 << 0
811};
813
814/*
815 Represents a command list of render commands that can be recorded on a thread and submitted. Recording is done using the FRecordScope which
816 sets the command list in TLS, diverting any render commands enqueued via ENQUEUE_RENDER_COMMAND into the command list. Command lists can
817 submit into other command lists as well as the main render command pipes. Command lists are useful for a couple reasons. First, the cost
818 of queuing commands into command lists is very light when recording into command lists as there are no locks, at the cost of deferring
819 submission of the work. Second, command lists can be submitted and recorded asynchronously from each other.
820
821 Command lists actually contain several sub-command lists, one for each render command pipe. At submission time the sub-command lists are
822 submitted separately. It doesn't matter if commands are enqueued to a pipe, they all go into the same command list.
823
824 Command lists have two operations, Close and Submit. Call Close when recording is complete. Call Submit to patch the command list into a parent
825 command list or the global render command pipes. Use FRenderCommandDispatcher::Submit to submit command lists.
826
827 Command lists support a fast-path with ERenderCommandListFlags::CloseOnSubmit. This fuses the Close / Submit operations but enables an optimization
828 to skip empty lists at the end, which is helpful when managing a large number of command lists (see FParallelForContext for a concrete use case).
829*/
830class FRenderCommandList final : public TConcurrentLinearObject<FRenderCommandList>
831{
832 friend class FRenderCommandPipe;
835
836 static thread_local FRenderCommandList* InstanceTLS;
837 static RENDERCORE_API FRenderCommandList* GetInstanceTLS();
838 static RENDERCORE_API FRenderCommandList* SetInstanceTLS(FRenderCommandList* CommandList);
839
840public:
842
847
849
851 {
852 None,
853
854 // Calls Close on the command list when the scope is complete.
855 Close,
856
857 // Calls Close and Submit on the command list when the scope is complete.
858 Submit
859 };
860
861 // A scope to bind a command list for recording on the current thread.
863 {
864 public:
867
868 FRecordScope(const FRecordScope&) = delete;
869
870 private:
871 FRenderCommandList* CommandList;
872 FRenderCommandList* PreviousCommandList;
873 EStopRecordingAction StopAction;
874 };
875
876 // A scope to unbind and flush the contents of the currently recording command list if there is one.
878 {
879 public:
882
883 FFlushScope(const FFlushScope&) = delete;
884
885 private:
886 FRenderCommandList* CommandList;
887 };
888
889 // Call when the command list recording is finished.
890 RENDERCORE_API void Close();
891
892 /*
893 A task context for use with parallel for that allocates a command list for each task thread.
894
895 Example Usage:
896
897 FRenderCommandList* ParentCommandList = FRenderCommandList::Create();
898
899 UE::Tasks::Launch(UE_SOURCE_LOCATION, [ParentCommandList]
900 {
901 // Closes recording of the command list on completion of the scope.
902 FRenderCommandList::FRecordScope RecordScope(ParentCommandList, FRenderCommandList::EStopRecordingAction::Close);
903
904 // Constructs a parallel for context with the command list as the root.
905 FRenderCommandList::FParallelForContext ParallelForContext(ParentCommandList, NumContexts);
906
907 // Issue a parallel with a command list per thread.
908 ParallelForWithExistingTaskContext(TEXT("ParallelFor"), ParallelForContext.GetCommandLists(), ..., [] (FRenderCommandList* InRenderCommandList)
909 {
910 FRenderCommandList::FRecordScope RecordScope(InRenderCommandList);
911
912 // Commands are recorded into InRenderCommandList.
913 });
914 });
915
916 ENQUEUE_RENDER_COMMAND(... [] { ... }); // Command A
917
918 // Submit the command list at any time. All included render commands are patched between commands A and C.
919 ParentCommandList->Submit();
920
921 ENQUEUE_RENDER_COMMAND(... [] { ... }); // Command C
922 */
924 {
925 public:
927 {
928 Submit();
929 }
930
933
935
937 {
938 return RootCommandList;
939 }
940
942 {
943 return TaskCommandLists;
944 }
945
946 RENDERCORE_API void Submit();
947
948 private:
949 FRenderCommandList* RootCommandList;
951 bool bSubmitRootCommandList = false;
952 };
953
955 {
956 if (DispatchTaskEvent)
957 {
958 return *DispatchTaskEvent;
959 }
960 return {};
961 }
962
963private:
965
968
969 const UE::Tasks::FTask* TryGetDispatchTask() const
970 {
971 return DispatchTaskEvent.GetPtrOrNull();
972 }
973
974 int32 ReleasePipeRefs(int32 InNumRefs)
975 {
976 int32 NumRefs = NumPipeRefs.fetch_sub(InNumRefs, std::memory_order_acq_rel) - InNumRefs;
977 check(NumRefs >= 0);
978 if (!NumRefs)
979 {
980 delete this;
981 }
982 return NumRefs;
983 }
984
985 int32 ReleasePipeRef()
986 {
987 return ReleasePipeRefs(1);
988 }
989
990 bool HasDispatchTask()
991 {
992 return DispatchTaskEvent.IsSet();
993 }
994
995 void LazyInit()
996 {
997 if (!bInitialized)
998 {
999 Init();
1000 }
1001 }
1002
1003 RENDERCORE_API void Init();
1004
1005 RENDERCORE_API void Flush();
1006
1007 template <typename RenderCommandTag, typename FunctionType>
1008 inline bool Enqueue(FunctionType&& Function)
1009 {
1010 return GetRenderThread().Enqueue<RenderCommandTag>(MoveTemp(Function));
1011 }
1012
1013 template <typename RenderCommandTag, typename FunctionType>
1014 inline bool Enqueue(FRenderCommandPipe* Pipe, FunctionType&& Function)
1015 {
1016 return Get(Pipe).Enqueue<RenderCommandTag>(MoveTemp(Function));
1017 }
1018
1019 inline UE::RenderCommandPipe::FCommandList& GetRenderThread()
1020 {
1021 LazyInit();
1022 return CommandLists.Last();
1023 }
1024
1026 {
1027 LazyInit();
1028 return CommandLists[PipeIndex];
1029 }
1030
1032 {
1033 LazyInit();
1034 return Pipe && Pipe->IsValid() ? CommandLists[Pipe->GetIndex()] : GetRenderThread();
1035 }
1036
1037 FMemStackBase Allocator;
1039 TOptional<UE::Tasks::FTaskEvent> DispatchTaskEvent;
1040
1041 std::atomic_int32_t NumPipeRefs = 0;
1042
1043 const ERenderCommandListFlags Flags;
1044 uint8 bInitialized : 1 = false;
1045 uint8 bRecording : 1 = true;
1046 uint8 bSubmitted : 1 = false;
1047
1048#if DO_CHECK
1050#endif
1051
1052 struct
1053 {
1056
1057 } Children;
1058
1059 FRenderCommandList* Parent = nullptr;
1060 FRenderCommandList* NextSibling = nullptr;
1061
1062 FRenderCommandPipeBitArray PipeEnqueueFailedBits;
1063
1064 friend class FRenderCommandDispatcher;
1065};
1066
1068{
1069public:
1079
1080 template <typename RenderCommandTag>
1082 {
1083#if !WITH_STATE_STREAM
1084 if (FRenderCommandList* CommandList = FRenderCommandList::GetInstanceTLS())
1085 {
1086 CommandList->Enqueue<RenderCommandTag>(MoveTemp(Function));
1087 return;
1088 }
1089#endif
1090
1091 FRenderThreadCommandPipe::Enqueue<RenderCommandTag>(MoveTemp(Function));
1092 }
1093
1094 template <typename RenderCommandTag>
1096 {
1097#if !WITH_STATE_STREAM
1098 if (FRenderCommandList* CommandList = FRenderCommandList::GetInstanceTLS())
1099 {
1100 CommandList->Enqueue<RenderCommandTag>(Pipe, MoveTemp(Function));
1101 return;
1102 }
1103
1105 {
1106 return;
1107 }
1108#endif
1109
1110 FRenderThreadCommandPipe::Enqueue<RenderCommandTag>([Function = MoveTemp(Function)](FRHICommandListImmediate& RHICmdList) { Function(RHICmdList); });
1111 }
1112
1113 template <typename RenderCommandTag>
1118
1119 template <typename RenderCommandTag>
1121 {
1122#if !WITH_STATE_STREAM
1123 if (FRenderCommandList* CommandListSet = FRenderCommandList::GetInstanceTLS())
1124 {
1126 return;
1127 }
1128
1130 {
1131 return;
1132 }
1133#endif
1134
1135 FRenderThreadCommandPipe::Enqueue<RenderCommandTag>([Function = MoveTemp(Function)](FRHICommandListImmediate&) { Function(); });
1136 }
1137
1138 template <typename RenderCommandTag>
1143};
1144
1146#define DECLARE_RENDER_COMMAND_PIPE(Name, PrefixKeywords) \
1147 namespace UE::RenderCommandPipe { extern PrefixKeywords FRenderCommandPipe Name; }
1148
1150#define DEFINE_RENDER_COMMAND_PIPE(Name, Flags) \
1151 namespace UE::RenderCommandPipe \
1152 { \
1153 FRenderCommandPipe Name( \
1154 TEXT(#Name), \
1155 Flags, \
1156 TEXT("r.RenderCommandPipe." #Name), \
1157 TEXT("Whether to enable the " #Name " Render Command Pipe") \
1158 TEXT(" 0: off;") \
1159 TEXT(" 1: on (default)") \
1160 ); \
1161 }
1162
1167#define ENQUEUE_RENDER_COMMAND(Type) \
1168 DECLARE_RENDER_COMMAND_TAG(PREPROCESSOR_JOIN(FRenderCommandTag_, PREPROCESSOR_JOIN(Type, __LINE__)), Type) \
1169 FRenderCommandDispatcher::Enqueue<PREPROCESSOR_JOIN(FRenderCommandTag_, PREPROCESSOR_JOIN(Type, __LINE__))>
1170
1172// RenderThread scoped work
1174
1176{
1178
1179 // Copy construction is not allowed. Used to avoid accidental copying in the command lambda.
1181
1184};
1185
1237template <typename StructType>
1239{
1240public:
1241 static_assert(TIsDerivedFrom<StructType, FRenderThreadStructBase>::IsDerived, "StructType must be derived from FRenderThreadStructBase.");
1242
1243 template <typename... TArgs>
1245 : Struct(new StructType(Forward<TArgs&&>(Args)...))
1246 {
1247 ENQUEUE_RENDER_COMMAND(InitStruct)([Struct = Struct](FRHICommandListImmediate& RHICmdList)
1248 {
1249 Struct->InitRHI(RHICmdList);
1250 });
1251 }
1252
1254 {
1255 ENQUEUE_RENDER_COMMAND(DeleteStruct)([Struct = Struct](FRHICommandListImmediate& RHICmdList)
1256 {
1257 Struct->ReleaseRHI(RHICmdList);
1258 delete Struct;
1259 });
1260 Struct = nullptr;
1261 }
1262
1264
1265 const StructType* operator->() const
1266 {
1267 return Struct;
1268 }
1269
1270 StructType* operator->()
1271 {
1272 return Struct;
1273 }
1274
1275 const StructType& operator*() const
1276 {
1277 return *Struct;
1278 }
1279
1280 StructType& operator*()
1281 {
1282 return *Struct;
1283 }
1284
1285 const StructType* Get() const
1286 {
1287 return Struct;
1288 }
1289
1290 StructType* Get()
1291 {
1292 return Struct;
1293 }
1294
1295private:
1296 StructType* Struct;
1297};
1298
1300using FStopRenderingThreadDelegate = FStopRenderingThread::FDelegate;
1301
1303
1305
1307// Deprecated Types
1308
1309class UE_DEPRECATED(5.6, "FRenderThreadScope is no longer used.") FRenderThreadScope
1310{
1311 typedef TFunction<void(FRHICommandListImmediate&)> RenderCommandFunction;
1312 typedef TArray<RenderCommandFunction> RenderCommandFunctionArray;
1313public:
1315 {
1316 RenderCommands = new RenderCommandFunctionArray;
1317 }
1318
1320 {
1321 RenderCommandFunctionArray* RenderCommandArray = RenderCommands;
1322
1325 {
1326 for(int32 Index = 0; Index < RenderCommandArray->Num(); Index++)
1327 {
1328 (*RenderCommandArray)[Index](RHICmdList);
1329 }
1330
1331 delete RenderCommandArray;
1332 });
1333 }
1334
1335 void EnqueueRenderCommand(RenderCommandFunction&& Lambda)
1336 {
1337 RenderCommands->Add(MoveTemp(Lambda));
1338 }
1339
1340private:
1341 RenderCommandFunctionArray* RenderCommands;
1342};
1343
1344class UE_DEPRECATED(5.6, "FRenderCommand is no longer used") FRenderCommand
1345{
1346public:
1347 static ENamedThreads::Type GetDesiredThread()
1348 {
1351 }
1352
1353 static ESubsequentsMode::Type GetSubsequentsMode()
1354 {
1356 }
1357};
1358
1359template <typename TagType, typename LambdaType>
1360class UE_DEPRECATED(5.6, "TEnqueueUniqueRenderCommandType is no longer used.") TEnqueueUniqueRenderCommandType : public FRenderCommand
1361{
1362public:
1364
1365 void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
1366 {
1369 Lambda(RHICmdList);
1370 }
1371
1372 inline TStatId GetStatId() const
1373 {
1374 return TagType::GetStatId();
1375 }
1376
1377private:
1378 LambdaType Lambda;
1379};
1380
1382
1383#undef UE_API
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
#define check(expr)
Definition AssertionMacros.h:314
#define ensure( InExpression)
Definition AssertionMacros.h:464
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ INDEX_NONE
Definition CoreMiscDefines.h:150
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
EParallelForFlags
Definition ParallelFor.h:47
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define DECLARE_STATS_GROUP(GroupDesc, GroupId, GroupCat)
Definition Stats.h:689
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define TRACE_CPUPROFILER_EVENT_SCOPE_USE_ON_CHANNEL(DeclName, NameStr, ScopeName, Channel, Condition)
Definition CpuProfilerTrace.h:517
#define TRACE_CPUPROFILER_EVENT_SCOPE_ON_CHANNEL_STR(NameStr, Channel)
Definition CpuProfilerTrace.h:525
#define DECLARE_MULTICAST_DELEGATE(DelegateName)
Definition DelegateCombinations.h:23
#define DECLARE_MULTICAST_DELEGATE_OneParam(DelegateName, Param1Type)
Definition DelegateCombinations.h:49
#define ENUM_CLASS_FLAGS(Enum)
Definition EnumClassFlags.h:6
RENDERCORE_API bool GIsThreadedRendering
Definition RenderingThread.cpp:48
FRHICommandListImmediate & GetImmediateCommandList_ForRenderCommand()
Definition RenderingThread.cpp:1330
FStopRenderingThread::FDelegate FStopRenderingThreadDelegate
Definition RenderingThread.h:1300
void CheckNotBlockedOnRenderThread()
Definition RenderingThread.h:80
RENDERCORE_API void FlushPendingDeleteRHIResources_GameThread()
Definition RenderingThread.cpp:1316
#define ShouldExecuteOnRenderThread()
Definition RenderingThread.h:155
RENDERCORE_API bool GUseThreadedRendering
Definition RenderingThread.cpp:49
RENDERCORE_API void ShutdownRenderingThread()
Definition RenderingThread.cpp:809
ERenderCommandPipeFlags
Definition RenderingThread.h:262
RENDERCORE_API TOptional< bool > GPendingUseThreadedRendering
Definition RenderingThread.cpp:50
RENDERCORE_API bool IsRenderingThreadHealthy()
Definition RenderingThread.cpp:840
RENDERCORE_API ERenderCommandPipeMode GRenderCommandPipeMode
Definition RenderingThread.cpp:136
RENDERCORE_API void FlushRenderingCommands()
Definition RenderingThread.cpp:1272
RENDERCORE_API TAtomic< bool > GMainThreadBlockedOnRenderThread
ERenderCommandPipeMode
Definition RenderingThread.h:250
RENDERCORE_API void StartRenderCommandFenceBundler()
Definition RenderingThread.cpp:874
RENDERCORE_API FDelegateHandle RegisterStopRenderingThreadDelegate(const FStopRenderingThreadDelegate &InDelegate)
Definition RenderingThread.cpp:659
ERenderCommandListFlags
Definition RenderingThread.h:806
#define ENQUEUE_RENDER_COMMAND(Type)
Definition RenderingThread.h:1167
RENDERCORE_API void AdvanceRenderingThreadStatsGT(bool bDiscardCallstack, int64 StatsFrame, int32 DisableChangeTagStartFrame)
Definition RenderingThread.cpp:308
RENDERCORE_API bool GIsThreadedRendering
Definition RenderingThread.cpp:48
RENDERCORE_API void FlushPendingDeleteRHIResources_RenderThread()
Definition RenderingThread.cpp:1325
RENDERCORE_API void UnregisterStopRenderingThreadDelegate(FDelegateHandle InDelegateHandle)
Definition RenderingThread.cpp:664
RENDERCORE_API void LatchRenderThreadConfiguration()
Definition RenderingThread.cpp:763
RENDERCORE_API void StopRenderCommandFenceBundler()
Definition RenderingThread.cpp:919
RENDERCORE_API void CheckRenderingThreadHealth()
Definition RenderingThread.cpp:817
RENDERCORE_API void InitRenderingThread()
Definition RenderingThread.cpp:795
RENDERCORE_API class FRHICommandListImmediate & GetImmediateCommandList_ForRenderCommand()
Definition RenderingThread.cpp:1330
TVariant< TUniqueFunction< void()>, TUniqueFunction< void(FRHICommandList &)>, TUniqueFunction< void(FRHICommandListImmediate &)> > FRenderCommandFunctionVariant
Definition RenderingThread.h:280
#define UE_API
Definition SColorGradingComponentViewer.h:12
CORE_API bool IsInParallelRenderingThread()
Definition ThreadingBase.cpp:301
CORE_API bool IsInGameThread()
Definition ThreadingBase.cpp:185
CORE_API bool IsInRenderingThread()
Definition ThreadingBase.cpp:273
#define UE_TRACE_CHANNEL_EXTERN(ChannelName,...)
Definition Trace.h:448
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
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition IConsoleManager.h:1471
Definition RenderingThread.h:121
static RENDERCORE_API FOnFlushRenderingCommandsEnd OnFlushRenderingCommandsEnd
Definition RenderingThread.h:127
static RENDERCORE_API FOnFlushRenderingCommandsStart OnFlushRenderingCommandsStart
Definition RenderingThread.h:124
DECLARE_MULTICAST_DELEGATE(FOnFlushRenderingCommandsStart)
DECLARE_MULTICAST_DELEGATE(FOnFlushRenderingCommandsEnd)
Definition IDelegateInstance.h:14
Definition MemStack.h:78
EPageSize
Definition MemStack.h:81
Definition UnrealType.h:3087
Definition RHICommandList.h:4626
Definition RHICommandList.h:3819
Definition RenderingThread.h:1068
static void Enqueue(FRenderCommandPipe &Pipe, FRenderCommandPipe::FEmptyFunction &&Function)
Definition RenderingThread.h:1139
static void Submit(FRenderCommandList *RenderCommandList, FRenderCommandList *ParentCommandList=nullptr)
Definition RenderingThread.h:1075
static void Enqueue(TUniqueFunction< void(FRHICommandListImmediate &)> &&Function)
Definition RenderingThread.h:1081
static void Enqueue(FRenderCommandPipe *Pipe, FRenderCommandPipe::FEmptyFunction &&Function)
Definition RenderingThread.h:1120
static void Enqueue(FRenderCommandPipe &Pipe, FRenderCommandPipe::FCommandListFunction &&Function)
Definition RenderingThread.h:1114
static void Enqueue(FRenderCommandPipe *Pipe, FRenderCommandPipe::FCommandListFunction &&Function)
Definition RenderingThread.h:1095
Definition RenderingThread.h:878
RENDERCORE_API FFlushScope()
Definition RenderingThread.cpp:1598
FFlushScope(const FFlushScope &)=delete
RENDERCORE_API ~FFlushScope()
Definition RenderingThread.cpp:1608
Definition RenderingThread.h:924
TArrayView< FRenderCommandList * > GetCommandLists()
Definition RenderingThread.h:941
~FParallelForContext()
Definition RenderingThread.h:926
RENDERCORE_API void Submit()
Definition RenderingThread.cpp:1643
FRenderCommandList * GetRootCommandList()
Definition RenderingThread.h:936
FParallelForContext(const FParallelForContext &)=delete
Definition RenderingThread.h:863
RENDERCORE_API ~FRecordScope()
Definition RenderingThread.cpp:1576
FRecordScope(const FRecordScope &)=delete
Definition RenderingThread.h:831
FMemStackBase::EPageSize EPageSize
Definition RenderingThread.h:841
FRenderCommandList * Head
Definition RenderingThread.h:1054
FRenderCommandList * Tail
Definition RenderingThread.h:1055
EStopRecordingAction
Definition RenderingThread.h:851
RENDERCORE_API void Close()
Definition RenderingThread.cpp:1726
static FRenderCommandList * Create(ERenderCommandListFlags InFlags=ERenderCommandListFlags::None, EPageSize InPageSize=EPageSize::Small)
Definition RenderingThread.h:843
UE::Tasks::FTask GetDispatchTask() const
Definition RenderingThread.h:954
RENDERCORE_API ~FRenderCommandList()
Definition RenderingThread.cpp:1677
Definition RenderingThread.h:489
~FRenderCommandPipeBase()
Definition RenderingThread.h:491
FContext * Context
Definition RenderingThread.h:527
UE::FMutex Mutex
Definition RenderingThread.h:528
void ResetContext()
Definition RenderingThread.h:497
Definition RenderingThread.cpp:1965
Definition RenderingThread.h:652
TUniqueFunction< void()> FEmptyFunction
Definition RenderingThread.h:655
const TCHAR * GetName() const
Definition RenderingThread.h:659
bool IsValid() const
Definition RenderingThread.h:664
bool Enqueue(FEmptyFunction &Function)
Definition RenderingThread.h:738
TUniqueFunction< void(FRHICommandList &)> FCommandListFunction
Definition RenderingThread.h:654
bool Enqueue(FRenderCommandList *RenderCommandList)
Definition RenderingThread.h:699
bool Enqueue(FCommandListFunction &Function)
Definition RenderingThread.h:717
bool IsRecording() const
Definition RenderingThread.h:681
bool IsEmpty() const
Definition RenderingThread.h:686
bool IsReplaying() const
Definition RenderingThread.h:675
int32 GetIndex() const
Definition RenderingThread.h:669
void SetEnabled(bool bInIsEnabled)
Definition RenderingThread.h:691
Definition RenderingThread.h:159
uint32 & GetSpecId() const
Definition RenderingThread.h:171
FRenderCommandTag(const TCHAR *InName, TStatId InStatId)
Definition RenderingThread.h:177
TStatId GetStatId() const
Definition RenderingThread.h:166
const TCHAR * GetName() const
Definition RenderingThread.h:161
Definition RenderingThread.h:532
static void Enqueue(FRenderCommandList *CommandList)
Definition RenderingThread.h:619
static void Enqueue(LambdaType &&Lambda)
Definition RenderingThread.h:594
Definition LightweightStats.h:424
Definition RHI.Build.cs:8
Definition ArrayView.h:139
Definition Array.h:670
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
Definition ConcurrentLinearAllocator.h:571
Definition BitArray.h:1944
Definition AndroidPlatformMisc.h:14
FGraphEventRef ConstructAndDispatchWhenReady(T &&... Args)
Definition TaskGraphInterfaces.h:614
Definition TaskGraphInterfaces.h:598
static FConstructor CreateTask(const FGraphEventArray *Prerequisites=nullptr, ENamedThreads::Type CurrentThreadIfKnown=ENamedThreads::AnyThread)
Definition TaskGraphInterfaces.h:664
Definition List.h:285
Definition RenderingThread.h:191
static const TRenderCommandTag & Get()
Definition RenderingThread.h:193
Definition RenderingThread.h:1239
TRenderThreadStruct(const TRenderThreadStruct &)=delete
StructType * Get()
Definition RenderingThread.h:1290
const StructType * operator->() const
Definition RenderingThread.h:1265
StructType * operator->()
Definition RenderingThread.h:1270
~TRenderThreadStruct()
Definition RenderingThread.h:1253
const StructType * Get() const
Definition RenderingThread.h:1285
const StructType & operator*() const
Definition RenderingThread.h:1275
TRenderThreadStruct(TArgs &&... Args)
Definition RenderingThread.h:1244
StructType & operator*()
Definition RenderingThread.h:1280
Definition ContainerAllocationPolicies.h:894
Definition FunctionFwd.h:19
Definition InheritedContext.h:118
void CaptureInheritedContext()
Definition InheritedContext.h:121
Definition InheritedContext.h:54
Definition Mutex.h:18
Definition RenderingThread.h:325
bool Enqueue(FRenderCommandFunctionVariant &&Function)
Definition RenderingThread.h:401
FCommandList(FMemStackBase &InAllocator)
Definition RenderingThread.h:371
void Close()
Definition RenderingThread.h:410
int32 Num
Definition RenderingThread.h:474
FCommand * Head
Definition RenderingThread.h:472
bool IsEmpty() const
Definition RenderingThread.h:452
void ConsumeCommands(const LambdaType &Lambda)
Definition RenderingThread.h:418
~FCommandList()
Definition RenderingThread.h:389
bool Enqueue(FunctionType &&Function)
Definition RenderingThread.h:395
int32 NumCommands() const
Definition RenderingThread.h:447
FCommandList(FMemStackBase &InAllocator, FCommandList &CommandListToConsume)
Definition RenderingThread.h:376
FCommand * Tail
Definition RenderingThread.h:473
Definition RenderingThread.h:313
UE_API FSyncScope()
Definition RenderingThread.cpp:2286
UE_API ~FSyncScope()
Definition RenderingThread.cpp:2310
Definition ScopeLock.h:21
bool IsValid() const
Definition Task.h:62
Definition RHICommandList.h:4571
UE_FORCEINLINE_HINT Type GetRenderThread()
Definition TaskGraphInterfaces.h:123
Type
Definition TaskGraphInterfaces.h:57
@ GameThread
Definition TaskGraphInterfaces.h:61
Type
Definition TaskGraphInterfaces.h:249
@ FireAndForget
Definition TaskGraphInterfaces.h:253
Definition UnrealEngine.cpp:13678
EFlushMode
Definition RenderingThread.h:46
Definition RenderingThread.cpp:1469
Definition AdvancedWidgetsModule.cpp:13
U16 Index
Definition radfft.cpp:71
EMemoryCounterRegion
Definition GenericPlatformMemory.h:249
@ MCR_Invalid
Definition GenericPlatformMemory.h:250
Definition RenderingThread.h:511
bool bDeleteAfterExecute
Definition RenderingThread.h:524
FContext(FContext &&Other)
Definition RenderingThread.h:517
FMemStackBase Allocator
Definition RenderingThread.h:522
FContext()
Definition RenderingThread.h:512
UE::RenderCommandPipe::FCommandList CommandList
Definition RenderingThread.h:523
Definition RenderingThread.h:1176
FRenderThreadStructBase()=default
FRenderThreadStructBase(const FRenderThreadStructBase &)=delete
void ReleaseRHI(FRHICommandListImmediate &)
Definition RenderingThread.h:1183
void InitRHI(FRHICommandListImmediate &)
Definition RenderingThread.h:1182
Definition TVariant.h:13
Definition UnrealTypeTraits.h:40
Definition Optional.h:131
constexpr bool IsSet() const
Definition Optional.h:69
constexpr OptionalType * GetPtrOrNull()
Definition Optional.h:478
Definition LightweightStats.h:416