UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
RHIValidationCommon.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3/*=============================================================================
4 ValidationRHICommon.h: Public Validation RHI definitions.
5=============================================================================*/
6
7#pragma once
8
10#include "PixelFormat.h"
11#include "RHIPipeline.h"
12#include "RHIStrings.h"
13#include "RHIAccess.h"
14#include "RHIBreadcrumbs.h"
15#include "Templates/TypeHash.h"
16
17#if ENABLE_RHI_VALIDATION
19#else
20const bool GRHIValidationEnabled = false;
21#endif
22
23#if ENABLE_RHI_VALIDATION
24
25class FRHIShader;
30class FRHITexture;
31
35class FValidationRHI;
36
40struct FRHIViewDesc;
41
46
48enum class ERayTracingBindingType : uint8;
51
52namespace RHIValidation
53{
55 {
58
59 void Reset();
61 };
62
64 {
66 void Reset();
68
70 };
71
73 {
74 void Reset();
76
78 };
79
80 class FTracker;
81 class FResource;
82 class FTextureResource;
83 struct FOperation;
84 struct FSubresourceState;
85 struct FSubresourceRange;
86 struct FResourceIdentity;
87
88 enum class ELoggingMode
89 {
90 None,
91 Manual,
93 };
94
95 enum class EResourcePlane
96 {
97 // Common plane index. Used for all resources
98 Common = 0,
99
100 // Additional plane indices for depth stencil resources
101 Stencil = 1,
102 Htile = 0, // @todo: do we need to track htile resources?
103
104 // Additional plane indices for color render targets
105 Cmask = 0, // @todo: do we need to track cmask resources?
106 Fmask = 0, // @todo: do we need to track fmask resources?
107
108 Max = 2
109 };
110
111 struct FSubresourceIndex
112 {
113 static constexpr int32 kWholeResource = -1;
114
115 int32 MipIndex;
116 int32 ArraySlice;
117 int32 PlaneIndex;
118
119 constexpr FSubresourceIndex()
120 : MipIndex(kWholeResource)
121 , ArraySlice(kWholeResource)
122 , PlaneIndex(kWholeResource)
123 {}
124
125 constexpr FSubresourceIndex(int32 InMipIndex, int32 InArraySlice, int32 InPlaneIndex)
126 : MipIndex(InMipIndex)
127 , ArraySlice(InArraySlice)
128 , PlaneIndex(InPlaneIndex)
129 {}
130
131 inline bool IsWholeResource() const
132 {
133 return MipIndex == kWholeResource
134 && ArraySlice == kWholeResource
135 && PlaneIndex == kWholeResource;
136 }
137 };
138
139 struct FState
140 {
141 ERHIAccess Access;
142 ERHIPipeline Pipelines;
143
144 FState() = default;
145
147 : Access(InAccess)
148 , Pipelines(InPipelines)
149 {}
150
151 inline bool operator == (const FState& RHS) const
152 {
153 return Access == RHS.Access &&
154 Pipelines == RHS.Pipelines;
155 }
156
157 inline bool operator != (const FState& RHS) const
158 {
159 return !(*this == RHS);
160 }
161
162 inline FString ToString() const
163 {
164 return FString::Printf(TEXT("Access: %s, Pipelines: %s"),
165 *GetRHIAccessName(Access),
166 *GetRHIPipelineName(Pipelines));
167 }
168 };
169
170 struct FSubresourceState
171 {
172 struct FPipelineState
173 {
175 {
179 }
180
181 FState Previous;
182 FState Current;
184
185 // True when a BeginTransition has been issued, and false when the transition has been ended.
186 bool bTransitioning = false;
187
188 // True when a transition with EResourceTransitionFlags::IgnoreAfterState happened, another transition with EResourceTransitionFlags::IgnoreAfterState needs to happen before a regular one
189 bool bIgnoringAfterState = false;
190
191 // True when the resource has been used within a Begin/EndUAVOverlap region.
192 bool bUsedWithAllUAVsOverlap = false;
193
194 // True if the calling code explicitly enabled overlapping on this UAV.
195 bool bExplicitAllowUAVOverlap = false;
196 bool bUsedWithExplicitUAVsOverlap = false;
197
198 // Pointer to the previous create/begin transition backtraces if logging is enabled for this resource.
199 void* CreateTransitionBacktrace = nullptr;
200 void* BeginTransitionBacktrace = nullptr;
201 };
202
205
206 void BeginTransition (FResource* Resource, FSubresourceIndex const& SubresourceIndex, const FState& CurrentStateFromRHI, const FState& TargetState, EResourceTransitionFlags NewFlags, ERHITransitionCreateFlags CreateFlags, ERHIPipeline Pipeline, const TRHIPipelineArray<uint64>& PipelineMaxAwaitedFenceValues, void* CreateTrace);
207 void EndTransition (FResource* Resource, FSubresourceIndex const& SubresourceIndex, const FState& CurrentStateFromRHI, const FState& TargetState, EResourceTransitionFlags NewFlags, ERHIPipeline Pipeline, uint64 PipelineFenceValue, void* CreateTrace);
208 void Assert (FResource* Resource, FSubresourceIndex const& SubresourceIndex, const FState& RequiredState, bool bAllowAllUAVsOverlap);
209 void AssertTracked (FResource* Resource, FSubresourceIndex const& SubresourceIndex, const FState& RequiredState, ERHIPipeline ExecutingPipeline);
210 void SpecificUAVOverlap(FResource* Resource, FSubresourceIndex const& SubresourceIndex, ERHIPipeline Pipeline, bool bAllow);
211 };
212
213 struct FSubresourceRange
214 {
215 uint32 MipIndex, NumMips;
216 uint32 ArraySlice, NumArraySlices;
217 uint32 PlaneIndex, NumPlanes;
218
219 FSubresourceRange() = default;
220
222 : MipIndex(InMipIndex)
224 , ArraySlice(InArraySlice)
225 , NumArraySlices(InNumArraySlices)
226 , PlaneIndex(InPlaneIndex)
227 , NumPlanes(InNumPlanes)
228 {}
229
230 inline bool operator == (FSubresourceRange const& RHS) const
231 {
232 return MipIndex == RHS.MipIndex
233 && NumMips == RHS.NumMips
234 && ArraySlice == RHS.ArraySlice
235 && NumArraySlices == RHS.NumArraySlices
236 && PlaneIndex == RHS.PlaneIndex
237 && NumPlanes == RHS.NumPlanes;
238 }
239
240 inline bool operator != (FSubresourceRange const& RHS) const
241 {
242 return !(*this == RHS);
243 }
244
245 inline bool IsWholeResource(FResource& Resource) const;
246 };
247
248 inline uint32 GetTypeHash(const FSubresourceRange& Range)
249 {
250 uint32 Hash = HashCombineFast(Range.MipIndex, Range.NumMips);
251 Hash = HashCombineFast(Hash, Range.ArraySlice);
252 Hash = HashCombineFast(Hash, Range.NumArraySlices);
253 Hash = HashCombineFast(Hash, Range.PlaneIndex);
254 Hash = HashCombineFast(Hash, Range.NumPlanes);
255 return Hash;
256 }
257
258 struct FResourceIdentity
259 {
260 FResource* Resource;
261 FSubresourceRange SubresourceRange;
262
263 FResourceIdentity() = default;
264
265 inline bool operator == (FResourceIdentity const& RHS) const
266 {
267 return Resource == RHS.Resource
268 && SubresourceRange == RHS.SubresourceRange;
269 }
270
271 inline bool operator != (FResourceIdentity const& RHS) const
272 {
273 return !(*this == RHS);
274 }
275 };
276
278 {
281 return Hash;
282 }
283
284 struct FViewIdentity : public FResourceIdentity
285 {
286 uint32 Stride = 0;
287
288 RHI_API FViewIdentity(FRHIViewableResource* Resource, FRHIViewDesc const& ViewDesc);
289 };
290
291 struct FTransientState
292 {
293 FTransientState() = default;
294
295 enum class EStatus : uint8
296 {
297 None,
298 Acquired,
300 };
301
303 : bTransient(InitialAccess == ERHIAccess::Discard)
304 {}
305
306 void* AcquireBacktrace = nullptr;
308
309 bool bTransient = false;
310 EStatus Status = EStatus::None;
311
312 inline bool IsAcquired() const { return Status == EStatus::Acquired; }
313 inline bool IsDiscarded() const { return Status == EStatus::Discarded; }
314
315 void Acquire(FResource* Resource, void* CreateTrace, ERHIPipeline ExecutingPipeline);
317
318 static void AliasingOverlap(FResource* ResourceBefore, FResource* ResourceAfter, void* CreateTrace);
319 };
320
321 class FResource
322 {
323 friend FTracker;
324 friend FTextureResource;
325 friend FOperation;
326 friend FSubresourceState;
327 friend FSubresourceRange;
328 friend FTransientState;
329 friend FValidationRHI;
330
331 protected:
332 uint32 NumMips = 0;
333 uint32 NumArraySlices = 0;
334 uint32 NumPlanes = 0;
337
338 private:
339 FString DebugName;
340
343
345
346 inline void EnumerateSubresources(FSubresourceRange const& SubresourceRange, TFunctionRef<void(FSubresourceState&, FSubresourceIndex const&)> Callback, bool bBeginTransition = false);
347
348 public:
349 ~FResource()
350 {
351 checkf(NumOpRefs.GetValue() == 0, TEXT("RHI validation resource '%s' is being deleted, but it is still queued in the replay command stream!"), *DebugName);
352 }
353
354 ELoggingMode LoggingMode = ELoggingMode::None;
355
356 RHI_API void SetDebugName(const TCHAR* Name, const TCHAR* Suffix = nullptr);
357 inline const TCHAR* GetDebugName() const { return DebugName.Len() ? *DebugName : nullptr; }
358
359 inline bool IsBarrierTrackingInitialized() const { return NumMips > 0 && NumArraySlices > 0; }
360
361 inline void AddOpRef() const
362 {
363 NumOpRefs.Increment();
364 }
365
366 inline void ReleaseOpRef() const
367 {
368 const int32 RefCount = NumOpRefs.Decrement();
369 check(RefCount >= 0);
370 }
371
372 inline FState GetTrackedState() const
373 {
374 return TrackedState;
375 }
376
377 inline uint32 GetNumSubresources() const
378 {
379 return NumMips * NumArraySlices * NumPlanes;
380 }
381
383 {
384 checkSlow(NumMips > 0 && NumArraySlices > 0 && NumPlanes > 0);
385
386 FSubresourceRange SubresourceRange;
387 SubresourceRange.MipIndex = 0;
388 SubresourceRange.ArraySlice = 0;
389 SubresourceRange.PlaneIndex = 0;
390 SubresourceRange.NumMips = NumMips;
391 SubresourceRange.NumArraySlices = NumArraySlices;
392 SubresourceRange.NumPlanes = NumPlanes;
393 return SubresourceRange;
394 }
395
397 {
398 FResourceIdentity Identity;
399 Identity.Resource = this;
400 Identity.SubresourceRange = GetWholeResourceRange();
401 return Identity;
402 }
403
404 void InitTransient(const TCHAR* InDebugName);
405
406 protected:
408 };
409
410 inline bool FSubresourceRange::IsWholeResource(FResource& Resource) const
411 {
412 return MipIndex == 0
413 && ArraySlice == 0
414 && PlaneIndex == 0
415 && NumMips == Resource.NumMips
416 && NumArraySlices == Resource.NumArraySlices
417 && NumPlanes == Resource.NumPlanes;
418 }
419
420 class FBufferResource : public FResource
421 {
422 public:
423 FBufferResource() = default;
425
426 RHI_API void InitBarrierTracking(const FRHIBufferCreateDesc& CreateDesc);
427 };
428
430 {
431 public:
433 {
434 FResource::InitBarrierTracking(1, 1, 1, InResourceState, InDebugName);
435 }
436 };
437
438 class FTextureResource
439 {
440 private:
441 // Don't use inheritance here. Because FRHITextureReferences exist, we have to
442 // call through a virtual to get the real underlying tracker resource from an FRHITexture*.
443 FResource PRIVATE_TrackerResource;
444
446
447 public:
448 FTextureResource() = default;
450
451 virtual ~FTextureResource() {}
452
453 virtual FResource* GetTrackerResource() { return &PRIVATE_TrackerResource; }
454
455 RHI_API void InitBarrierTracking(FRHITextureCreateDesc const& CreateDesc);
456
457 inline bool IsBarrierTrackingInitialized() const
458 {
459 // @todo: clean up const_cast once FRHITextureReference is removed and
460 // we don't need to keep a separate PRIVATE_TrackerResource object.
461 return const_cast<FTextureResource*>(this)->GetTrackerResource()->IsBarrierTrackingInitialized();
462 }
463
466
469
471 {
472 return GetTrackerResource()->GetWholeResourceIdentity();
473 }
474
476 {
478
479 // When binding a whole texture for shader read (SRV), we only use the first plane.
480 // Other planes like stencil require a separate view to access for read in the shader.
481 Identity.SubresourceRange.NumPlanes = 1;
482
483 return Identity;
484 }
485 };
486
488 {
489 public:
490
492 RHI_API FRHIRayTracingShader* GetShader(ERayTracingBindingType BindingType, uint32 Index) const;
493
494 private:
495
496 // Cache the RHIShaders per binding type so they can be retrieved during SetBindingsOnShaderBindingTable to find all the used resources for a certain RHIShader
500 };
501
502 struct FUAVBinding
503 {
504 FRHIUnorderedAccessView* UAV = nullptr;
505 uint32 Slot = 0;
506
507 inline bool operator == (FUAVBinding const& RHS) const
508 {
509 return UAV == RHS.UAV
510 && Slot == RHS.Slot;
511 }
512
513 inline bool operator != (FUAVBinding const& RHS) const
514 {
515 return !(*this == RHS);
516 }
517 };
518
520 {
523 return Hash;
524 }
525
527 {
528 public:
529
531
532 RHI_API void Clear();
533 RHI_API void SetBindingsOnShaderBindingTable(FRayTracingPipelineState* RayTracingPipelineState, uint32 NumBindings, const FRayTracingLocalShaderBindings* Bindings, ERayTracingBindingType BindingType);
534 RHI_API void Commit();
535
536 RHI_API void ValidateStateForDispatch(RHIValidation::FTracker* Tracker) const;
537
538 void AddSRV(const FResourceIdentity& ResourceIdentity, uint32 WorkerIndex)
539 {
540 WorkerData[WorkerIndex].SRVs.Add(ResourceIdentity);
541 }
542
544 {
545 WorkerData[WorkerIndex].UAVs.Add({ UAV, InSlot });
546 }
547
548 private:
549
551 ERayTracingShaderBindingMode ShaderBindingMode;
552 ERayTracingHitGroupIndexingMode HitGroupIndexingMode;
553 bool bIsDirty = true;
554
555 struct FWorkerThreadData
556 {
559 };
560
561 static constexpr uint32 MaxBindingWorkers = 5; // RHI thread + 4 parallel workers.
562 FWorkerThreadData WorkerData[MaxBindingWorkers];
563 };
564
565 struct FFence
566 {
567 bool bSignaled = false;
570 uint64 FenceValue = 0;
571 };
572
573 enum class EOpType
574 {
575 BeginTransition
576 , EndTransition
577 , SetTrackedAccess
582 , Assert
583 , Rename
584 , Signal
585 , Wait
588#if WITH_RHI_BREADCRUMBS
592#endif
593 };
594
596 {
598 bool bContainsNullContents = false;
599 EUniformBufferUsage UniformBufferUsage;
600 void* AllocatedCallstack;
601
602 void InitLifetimeTracking(uint64 FrameID, const void* Contents, EUniformBufferUsage Usage);
603 void UpdateAllocation(uint64 FrameID);
604 void ValidateLifeTime();
605 };
606
607 struct FOpQueueState;
608
609 struct FOperation
610 {
612
613 union
614 {
615 struct
616 {
617 FResourceIdentity Identity;
618 FState PreviousState;
619 FState NextState;
621 ERHITransitionCreateFlags CreateFlags;
622 void* CreateBacktrace;
624
625 struct
626 {
627 FResourceIdentity Identity;
628 FState PreviousState;
629 FState NextState;
631 void* CreateBacktrace;
633
634 struct
635 {
636 FResource* Resource;
637 FState State;
639
640 struct
641 {
642 FResource* ResourceBefore;
643 FResource* ResourceAfter;
644 void* CreateBacktrace;
646
647 struct
648 {
649 FResource* Resource;
650 void* CreateBacktrace;
652
653 struct
654 {
655 FResource* Resource;
656 TCHAR* DebugName;
658
659 struct
660 {
661 FResourceIdentity Identity;
662 FState RequiredState;
663 } Data_Assert;
664
665 struct
666 {
667 FResource* Resource;
668 TCHAR* DebugName;
669 const TCHAR* Suffix;
670 } Data_Rename;
671
672 struct
673 {
674 FFence* Fence;
675 } Data_Signal;
676
677 struct
678 {
679 FFence* Fence;
680 } Data_Wait;
681
682 struct
683 {
684 bool bAllow;
686
687 struct
688 {
689 FResourceIdentity Identity;
690 bool bAllow;
692
693#if WITH_RHI_BREADCRUMBS
694 struct
695 {
698
699 struct
700 {
703#endif // WITH_RHI_BREADCRUMBS
704 };
705
706 // Returns true if the operation is complete
707 RHI_API bool Replay(FOpQueueState& Queue) const;
708
709 static inline FOperation BeginTransitionResource(FResourceIdentity Identity, FState PreviousState, FState NextState, EResourceTransitionFlags Flags, ERHITransitionCreateFlags CreateFlags, void* CreateBacktrace)
710 {
711 for (ERHIPipeline Pipeline : MakeFlagsRange(PreviousState.Pipelines))
712 {
713 Identity.Resource->AddOpRef();
714 }
715
716 FOperation Op;
717 Op.Type = EOpType::BeginTransition;
718 Op.Data_BeginTransition.Identity = Identity;
719 Op.Data_BeginTransition.PreviousState = PreviousState;
720 Op.Data_BeginTransition.NextState = NextState;
721 Op.Data_BeginTransition.Flags = Flags;
722 Op.Data_BeginTransition.CreateFlags = CreateFlags;
723 Op.Data_BeginTransition.CreateBacktrace = CreateBacktrace;
724 return MoveTemp(Op);
725 }
726
727 static inline FOperation EndTransitionResource(FResourceIdentity Identity, FState PreviousState, FState NextState, EResourceTransitionFlags Flags, void* CreateBacktrace)
728 {
729 for (ERHIPipeline Pipeline : MakeFlagsRange(NextState.Pipelines))
730 {
731 Identity.Resource->AddOpRef();
732 }
733
734 FOperation Op;
735 Op.Type = EOpType::EndTransition;
736 Op.Data_EndTransition.Identity = Identity;
737 Op.Data_EndTransition.PreviousState = PreviousState;
738 Op.Data_EndTransition.NextState = NextState;
739 Op.Data_EndTransition.Flags = Flags;
740 Op.Data_EndTransition.CreateBacktrace = CreateBacktrace;
741 return MoveTemp(Op);
742 }
743
744 static inline FOperation SetTrackedAccess(FResource* Resource, FState State)
745 {
746 Resource->AddOpRef();
747
748 FOperation Op;
749 Op.Type = EOpType::SetTrackedAccess;
750 Op.Data_SetTrackedAccess.Resource = Resource;
751 Op.Data_SetTrackedAccess.State = State;
752 return MoveTemp(Op);
753 }
754
755 static inline FOperation AliasingOverlap(FResource* ResourceBefore, FResource* ResourceAfter, void* CreateBacktrace)
756 {
757 ResourceBefore->AddOpRef();
758 ResourceAfter->AddOpRef();
759
760 FOperation Op;
761 Op.Type = EOpType::AliasingOverlap;
762 Op.Data_AliasingOverlap.ResourceBefore = ResourceBefore;
763 Op.Data_AliasingOverlap.ResourceAfter = ResourceAfter;
764 Op.Data_AliasingOverlap.CreateBacktrace = CreateBacktrace;
765 return Op;
766 }
767
768 static inline FOperation AcquireTransientResource(FResource* Resource, void* CreateBacktrace)
769 {
770 Resource->AddOpRef();
771
772 FOperation Op;
773 Op.Type = EOpType::AcquireTransient;
774 Op.Data_AcquireTransient.Resource = Resource;
775 Op.Data_AcquireTransient.CreateBacktrace = CreateBacktrace;
776 return MoveTemp(Op);
777 }
778
779 static inline FOperation InitTransient(FResource* Resource, const TCHAR* DebugName)
780 {
781 Resource->AddOpRef();
782
783 FOperation Op;
784 Op.Type = EOpType::InitTransient;
785 Op.Data_InitTransient.Resource = Resource;
786 AllocStringCopy(Op.Data_InitTransient.DebugName, DebugName);
787
788 return MoveTemp(Op);
789 }
790
791 static inline FOperation Assert(FResourceIdentity Identity, FState RequiredState)
792 {
793 Identity.Resource->AddOpRef();
794
795 FOperation Op;
796 Op.Type = EOpType::Assert;
797 Op.Data_Assert.Identity = Identity;
798 Op.Data_Assert.RequiredState = RequiredState;
799 return MoveTemp(Op);
800 }
801
802 static inline FOperation Rename(FResource* Resource, const TCHAR* NewName, const TCHAR* Suffix = nullptr)
803 {
804 Resource->AddOpRef();
805
806 FOperation Op;
807 Op.Type = EOpType::Rename;
808 Op.Data_Rename.Resource = Resource;
809 AllocStringCopy(Op.Data_Rename.DebugName, NewName);
810 Op.Data_Rename.Suffix = Suffix;
811 return MoveTemp(Op);
812 }
813
814 static inline FOperation Signal(FFence* Fence)
815 {
816 FOperation Op;
817 Op.Type = EOpType::Signal;
818 Op.Data_Signal.Fence = Fence;
819 return MoveTemp(Op);
820 }
821
822 static inline FOperation Wait(FFence* Fence)
823 {
824 FOperation Op;
825 Op.Type = EOpType::Wait;
826 Op.Data_Wait.Fence = Fence;
827 return MoveTemp(Op);
828 }
829
830 static inline FOperation AllUAVsOverlap(bool bAllow)
831 {
832 FOperation Op;
833 Op.Type = EOpType::AllUAVsOverlap;
834 Op.Data_AllUAVsOverlap.bAllow = bAllow;
835 return MoveTemp(Op);
836 }
837
838 static inline FOperation SpecificUAVOverlap(FResourceIdentity Identity, bool bAllow)
839 {
840 Identity.Resource->AddOpRef();
841
842 FOperation Op;
843 Op.Type = EOpType::SpecificUAVOverlap;
844 Op.Data_SpecificUAVOverlap.Identity = Identity;
845 Op.Data_SpecificUAVOverlap.bAllow = bAllow;
846 return MoveTemp(Op);
847 }
848
849#if WITH_RHI_BREADCRUMBS
851 {
852 check(Breadcrumb && Breadcrumb != FRHIBreadcrumbNode::Sentinel);
853
854 FOperation Op;
855 Op.Type = EOpType::BeginBreadcrumbGPU;
856 Op.Data_Breadcrumb.Breadcrumb = Breadcrumb;
857 return Op;
858 }
859
861 {
862 check(Breadcrumb && Breadcrumb != FRHIBreadcrumbNode::Sentinel);
863
864 FOperation Op;
865 Op.Type = EOpType::EndBreadcrumbGPU;
866 Op.Data_Breadcrumb.Breadcrumb = Breadcrumb;
867 return Op;
868 }
869
871 {
872 check(BreadcrumbRange.First != FRHIBreadcrumbNode::Sentinel);
873 check(BreadcrumbRange.Last != FRHIBreadcrumbNode::Sentinel);
874
875 FOperation Op;
876 Op.Type = EOpType::SetBreadcrumbRange;
877 Op.Data_BreadcrumbRange.Range = BreadcrumbRange;
878
879 return Op;
880 }
881#endif // WITH_RHI_BREADCRUMBS
882
883 private:
884 static inline void AllocStringCopy(TCHAR*& OutString, const TCHAR* InString)
885 {
887 OutString = new TCHAR[Len + 1];
888 FMemory::Memcpy(OutString, InString, Len * sizeof(TCHAR));
889 OutString[Len] = 0;
890 }
891 };
892
894 {
897
902 };
903
904 enum class EUAVMode
905 {
906 Graphics,
907 Compute,
908 Num
909 };
910
911 struct FOpQueueState
912 {
914 uint64 FenceValue = 0;
916
917#if WITH_RHI_BREADCRUMBS
918 struct
919 {
921 FRHIBreadcrumbNode* Current = nullptr;
922 } Breadcrumbs;
923#endif
924
925 bool bAllowAllUAVsOverlap = false;
926
927 struct FOpsList : public TArray<FOperation>
928 {
929 int32 ReplayPos = 0;
930
931 FOpsList(FOpsList&&) = default;
934 {}
935 };
936
938
941 {}
942
943 void AppendOps(FValidationCommandList* CommandList);
944
945 // Returns true if progress was made
946 bool Execute();
947 };
948
949 class FTracker
950 {
951 struct FUAVTracker
952 {
953 private:
955
956 public:
958 {
960 }
961
962 inline FRHIUnorderedAccessView*& operator[](int32 Slot)
963 {
964 if (Slot >= UAVs.Num())
965 {
966 UAVs.SetNumZeroed(Slot + 1);
967 }
968 return UAVs[Slot];
969 }
970
971 inline void Reset()
972 {
974 }
975
976 void DrawOrDispatch(FTracker* BarrierTracker, const FState& RequiredState);
977 };
978
979 public:
980 FTracker(ERHIPipeline InPipeline)
982 {}
983
984 RHI_API void AddOp(const FOperation& Op);
985
986 void AddOps(TArray<FOperation> const& List)
987 {
988 for (const FOperation& Op : List)
989 {
990 AddOp(Op);
991 }
992 }
993
995 {
996 return MoveTemp(CurrentList);
997 }
998
999#if WITH_RHI_BREADCRUMBS
1001 {
1002 AddOp(FOperation::BeginBreadcrumbGPU(Breadcrumb));
1003 }
1004
1006 {
1007 AddOp(FOperation::EndBreadcrumbGPU(Breadcrumb));
1008 }
1009#endif
1010
1011 void SetTrackedAccess(FResource* Resource, ERHIAccess Access, ERHIPipeline Pipelines)
1012 {
1013 AddOp(FOperation::SetTrackedAccess(Resource, FState(Access, Pipelines)));
1014 }
1015
1016 void Rename(FResource* Resource, const TCHAR* NewName, const TCHAR* Suffix = nullptr)
1017 {
1018 AddOp(FOperation::Rename(Resource, NewName, Suffix));
1019 }
1020
1022 {
1023 AddOp(FOperation::Assert(Identity, FState(RequiredAccess, Pipeline)));
1024 }
1025
1027 {
1028 checkSlow(Mode == EUAVMode::Compute || Pipeline == ERHIPipeline::Graphics);
1029 UAVTrackers[int32(Mode)][Slot] = UAV;
1030 }
1031
1033 {
1034 checkSlow(!(Access & ~ERHIAccess::UAVMask));
1035 AssertUAV(UAV, Access == ERHIAccess::UAVGraphics ? EUAVMode::Graphics : EUAVMode::Compute, Slot);
1036 }
1037
1038 void TransitionResource(FResourceIdentity Identity, FState PreviousState, FState NextState, EResourceTransitionFlags Flags)
1039 {
1040 // This function exists due to the implicit transitions that RHI functions make (e.g. RHICopyToResolveTarget).
1041 // It should be removed when we eventually remove all implicit transitions from the RHI.
1042 AddOp(FOperation::BeginTransitionResource(Identity, PreviousState, NextState, Flags, ERHITransitionCreateFlags::None, nullptr));
1043 AddOp(FOperation::EndTransitionResource(Identity, PreviousState, NextState, Flags, nullptr));
1044 }
1045
1046 void AllUAVsOverlap(bool bAllow)
1047 {
1048 AddOp(FOperation::AllUAVsOverlap(bAllow));
1049 }
1050
1051 void SpecificUAVOverlap(FResourceIdentity Identity, bool bAllow)
1052 {
1053 AddOp(FOperation::SpecificUAVOverlap(Identity, bAllow));
1054 }
1055
1056 void Dispatch()
1057 {
1058 UAVTrackers[int32(EUAVMode::Compute)].DrawOrDispatch(this, FState(ERHIAccess::UAVCompute, Pipeline));
1059 }
1060
1061 void Draw()
1062 {
1064 UAVTrackers[int32(EUAVMode::Graphics)].DrawOrDispatch(this, FState(ERHIAccess::UAVGraphics, Pipeline));
1065 }
1066
1067 void ResetUAVState(EUAVMode Mode)
1068 {
1069 UAVTrackers[int32(Mode)].Reset();
1070 }
1071
1072 void ResetAllUAVState()
1073 {
1075 {
1077 }
1078 }
1079
1080 static FOpQueueState& GetQueue(ERHIPipeline Pipeline);
1081
1083
1084 private:
1085 const ERHIPipeline Pipeline;
1087 FUAVTracker UAVTrackers[int32(EUAVMode::Num)];
1088
1089 friend FOperation;
1091 };
1092
1093 extern RHI_API void* CaptureBacktrace();
1094
1098
1101
1104
1105}
1106
1107#endif // ENABLE_RHI_VALIDATION
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
#define checkf(expr, format,...)
Definition AssertionMacros.h:315
@ InPlace
Definition CoreMiscDefines.h:162
#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::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
FPlatformTypes::uint64 uint64
A 64-bit unsigned integer.
Definition Platform.h:1117
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::EnumFlags::Private::TRange< EnumType > MakeFlagsRange(EnumType Flags)
Definition EnumRange.h:285
UE_FORCEINLINE_HINT bool operator!=(const FIndexedPointer &Other) const
Definition LockFreeList.h:76
@ Num
Definition MetalRHIPrivate.h:234
@ Compute
Definition MetalRHIPrivate.h:232
EPixelFormat
Definition PixelFormat.h:16
ERHIAccess
Definition RHIAccess.h:11
ERayTracingBindingType
Definition RHICommandList.h:281
EShaderFrequency
Definition RHIDefinitions.h:202
@ SF_NumFrequencies
Definition RHIDefinitions.h:216
EResourceTransitionFlags
Definition RHIDefinitions.h:1517
EUniformBufferUsage
Definition RHIDefinitions.h:536
ERHITransitionCreateFlags
Definition RHIDefinitions.h:1495
ETextureCreateFlags
Definition RHIDefinitions.h:1091
FRHIGlobals GRHIGlobals
Definition RHIGlobals.cpp:6
ERHIPipeline
Definition RHIPipeline.h:13
ERayTracingHitGroupIndexingMode
Definition RHIResources.h:3628
ERayTracingShaderBindingTableLifetime
Definition RHIResources.h:3613
ERayTracingShaderBindingMode
Definition RHIResources.h:3620
FString GetRHIPipelineName(ERHIPipeline Pipeline)
Definition RHIStrings.cpp:512
FString GetRHIAccessName(ERHIAccess Access)
Definition RHIStrings.cpp:466
const bool GRHIValidationEnabled
Definition RHIValidationCommon.h:20
constexpr uint32 HashCombineFast(uint32 A, uint32 B)
Definition TypeHash.h:74
uint32 PointerHash(const void *Key)
Definition TypeHash.h:91
#define UE_ARRAY_COUNT(array)
Definition UnrealTemplate.h:212
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint8_t uint8
Definition binka_ue_file_header.h:8
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition PipelineStateCache.cpp:712
Definition RHIResources.h:1115
Definition RHIResources.h:984
Definition RHIResources.h:3304
Definition RHIResources.h:854
Definition RHIResources.h:2153
Definition RHIResources.h:1232
Definition RHIResources.h:3294
Definition RHIResources.h:1265
Definition RHIResources.h:5023
Definition PipelineStateCache.cpp:1285
Definition TextureResource.h:103
Definition ThreadSafeCounter.h:14
Definition Array.h:670
UE_REWRITE SizeType Num() const
Definition Array.h:1144
void SetNumZeroed(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2340
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
UE_FORCEINLINE_HINT void Reserve(SizeType Number)
Definition Array.h:3016
Definition AssetRegistryState.h:50
Definition RHIPipeline.h:55
constexpr int32 NumMips
Definition DistanceFieldAtlas.h:44
@ Range
Definition EnvQueryTypes.h:81
@ Suffix
Definition MirrorDataTable.h:34
Type
Definition PawnAction_Move.h:11
@ List
Definition ITypedTableView.h:38
uint32 GetTypeHash(const FKey &Key)
Definition BlackboardKey.h:35
void Dispatch(FRHIComputeCommandList &RHICmdList, const TShaderRef< TShaderClass > &ComputeShader, const FShaderParametersMetadata *ParametersMetadata, const typename TShaderClass::FParameters &Parameters, FIntVector GroupCount)
Definition RenderGraphUtils.h:491
FString ToString(uint16 Value)
Definition PathFollowingComponent.cpp:82
FORCEINLINE T * Get(const FObjectPtr &ObjectPtr)
Definition ObjectPtr.h:426
void Draw(const FLinearBoundary &Boundary, const FRestrictionCurve &Curve, EVisuProperty Property)
Definition Display.cpp:95
State
Definition PacketHandler.h:88
UE_AUTORTFM_NOAUTORTFM FWaitState Wait(const void *Address, bool(*CanWait)(void *), void *CanWaitContext, void(*BeforeWait)(void *), void *BeforeWaitContext)
Definition ParkingLot.cpp:504
U16 Index
Definition radfft.cpp:71
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
Definition RHIResources.h:1417
static constexpr int32 MinGuaranteedSimultaneousUAVs
Definition RHIGlobals.h:347
Definition RHIResources.h:1938
Definition RHITransition.h:119
Definition RHIResources.h:2648
Definition RHICommandList.h:267
Definition RHIResources.h:3635
static int32 Strlen(const CharType *String)
Definition CString.h:1047