2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-07-16 13:08:56 -04:00
# include "RenderGraphValidation.h"
2020-07-06 18:58:26 -04:00
# include "RenderGraphPrivate.h"
# include "Misc/FileHelper.h"
# include "Misc/Paths.h"
2020-09-24 00:43:27 -04:00
# include "MultiGPU.h"
2019-07-16 13:08:56 -04:00
# if RDG_ENABLE_DEBUG
2020-07-06 18:58:26 -04:00
namespace
{
template < typename TFunction >
void EnumerateSubresources ( const FRHITransitionInfo & Transition , uint32 NumMips , uint32 NumArraySlices , uint32 NumPlaneSlices , TFunction Function )
{
uint32 MinMipIndex = 0 ;
uint32 MaxMipIndex = NumMips ;
uint32 MinArraySlice = 0 ;
uint32 MaxArraySlice = NumArraySlices ;
uint32 MinPlaneSlice = 0 ;
uint32 MaxPlaneSlice = NumPlaneSlices ;
if ( ! Transition . IsAllMips ( ) )
{
MinMipIndex = Transition . MipIndex ;
MaxMipIndex = MinMipIndex + 1 ;
}
if ( ! Transition . IsAllArraySlices ( ) )
{
MinArraySlice = Transition . ArraySlice ;
MaxArraySlice = MinArraySlice + 1 ;
}
if ( ! Transition . IsAllPlaneSlices ( ) )
{
MinPlaneSlice = Transition . PlaneSlice ;
MaxPlaneSlice = MinPlaneSlice + 1 ;
}
for ( uint32 PlaneSlice = MinPlaneSlice ; PlaneSlice < MaxPlaneSlice ; + + PlaneSlice )
{
for ( uint32 ArraySlice = MinArraySlice ; ArraySlice < MaxArraySlice ; + + ArraySlice )
{
for ( uint32 MipIndex = MinMipIndex ; MipIndex < MaxMipIndex ; + + MipIndex )
{
2020-09-24 00:43:27 -04:00
Function ( FRDGTextureSubresource ( MipIndex , ArraySlice , PlaneSlice ) ) ;
2020-07-06 18:58:26 -04:00
}
}
}
}
2020-09-24 00:43:27 -04:00
const ERHIAccess AccessMaskCopy = ERHIAccess : : CopySrc | ERHIAccess : : CopyDest | ERHIAccess : : CPURead ;
2020-11-05 11:20:37 -04:00
const ERHIAccess AccessMaskCompute = ERHIAccess : : SRVCompute | ERHIAccess : : UAVCompute ;
const ERHIAccess AccessMaskRaster = ERHIAccess : : ResolveSrc | ERHIAccess : : ResolveDst | ERHIAccess : : DSVRead | ERHIAccess : : DSVWrite | ERHIAccess : : RTV | ERHIAccess : : SRVGraphics | ERHIAccess : : UAVGraphics | ERHIAccess : : Present | ERHIAccess : : VertexOrIndexBuffer ;
const ERHIAccess AccessMaskComputeOrRaster = ERHIAccess : : IndirectArgs ;
2020-09-24 00:43:27 -04:00
2020-11-18 18:25:03 -04:00
/** Validates that only one builder instance exists at any time. This is currently a requirement for state tracking and allocation lifetimes. */
bool GRDGBuilderActive = false ;
2021-02-18 20:06:45 -04:00
2020-07-06 18:58:26 -04:00
} //! namespace
2019-07-16 13:08:56 -04:00
2020-11-17 17:04:48 -04:00
struct FRDGResourceDebugData
{
/** Boolean to track at runtime whether a resource is actually used by the lambda of a pass or not, to detect unnecessary resource dependencies on passes. */
bool bIsActuallyUsedByPass = false ;
/** Boolean to track at pass execution whether the underlying RHI resource is allowed to be accessed. */
bool bAllowRHIAccess = false ;
} ;
void FRDGResource : : MarkResourceAsUsed ( )
{
ValidateRHIAccess ( ) ;
2021-04-06 12:38:10 -04:00
GetDebugData ( ) . bIsActuallyUsedByPass = true ;
2020-11-17 17:04:48 -04:00
}
void FRDGResource : : ValidateRHIAccess ( ) const
{
2021-04-06 12:38:10 -04:00
check ( DebugData ) ;
2021-07-29 13:02:16 -04:00
checkf ( DebugData - > bAllowRHIAccess | | GRDGAllowRHIAccess ,
2021-04-06 12:38:10 -04:00
TEXT ( " Accessing the RHI resource of %s at this time is not allowed. If you hit this check in pass, " )
TEXT ( " that is due to this resource not being referenced in the parameters of your pass. " ) ,
Name ) ;
2020-11-17 17:04:48 -04:00
}
FRDGResourceDebugData & FRDGResource : : GetDebugData ( ) const
{
check ( DebugData ) ;
return * DebugData ;
}
struct FRDGParentResourceDebugData
{
/** Pointer towards the pass that is the first to produce it, for even more convenient error message. */
const FRDGPass * FirstProducer = nullptr ;
/** Count the number of times it has been used by a pass (without culling). */
uint32 PassAccessCount = 0 ;
/** Tracks whether this resource was clobbered by the builder prior to use. */
bool bHasBeenClobbered = false ;
2021-04-06 11:45:09 -04:00
/** Tracks which pass performed a finalize operation on the resource. */
FRDGPassHandle FinalizePass ;
2020-11-17 17:04:48 -04:00
} ;
FRDGParentResourceDebugData & FRDGParentResource : : GetParentDebugData ( ) const
{
check ( ParentDebugData ) ;
return * ParentDebugData ;
}
struct FRDGTextureDebugData
{
/** Tracks whether a UAV has ever been allocated to catch when TexCreate_UAV was unneeded. */
bool bHasNeededUAV = false ;
/** Tracks whether has ever been bound as a render target to catch when TexCreate_RenderTargetable was unneeded. */
bool bHasBeenBoundAsRenderTarget = false ;
} ;
FRDGTextureDebugData & FRDGTexture : : GetTextureDebugData ( ) const
{
check ( TextureDebugData ) ;
return * TextureDebugData ;
}
struct FRDGBufferDebugData
{
/** Tracks state changes in order of execution. */
2020-11-18 18:25:03 -04:00
TArray < TPair < FRDGPassHandle , FRDGSubresourceState > , FRDGArrayAllocator > States ;
2020-11-17 17:04:48 -04:00
} ;
FRDGBufferDebugData & FRDGBuffer : : GetBufferDebugData ( ) const
{
check ( BufferDebugData ) ;
return * BufferDebugData ;
}
void FRDGUniformBuffer : : MarkResourceAsUsed ( )
{
FRDGResource : : MarkResourceAsUsed ( ) ;
// Individual resources can't be culled from a uniform buffer, so we have to mark them all as used.
ParameterStruct . Enumerate ( [ ] ( FRDGParameter Parameter )
{
if ( FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
{
Resource - > MarkResourceAsUsed ( ) ;
}
} ) ;
}
2021-07-29 13:02:16 -04:00
FRDGUserValidation : : FRDGUserValidation ( FRDGAllocator & InAllocator , bool bInParallelExecuteEnabled )
2020-11-17 17:04:48 -04:00
: Allocator ( InAllocator )
2021-07-29 13:02:16 -04:00
, bParallelExecuteEnabled ( bInParallelExecuteEnabled )
2020-11-18 18:25:03 -04:00
{
checkf ( ! GRDGBuilderActive , TEXT ( " Another FRDGBuilder already exists on the stack. Only one builder can be created at a time. This builder instance should be merged into the parent one. " ) ) ;
GRDGBuilderActive = true ;
}
2020-10-23 16:26:52 -04:00
2019-07-16 13:08:56 -04:00
FRDGUserValidation : : ~ FRDGUserValidation ( )
{
checkf ( bHasExecuted , TEXT ( " Render graph execution is required to ensure consistency with immediate mode. " ) ) ;
}
void FRDGUserValidation : : ExecuteGuard ( const TCHAR * Operation , const TCHAR * ResourceName )
{
checkf ( ! bHasExecuted , TEXT ( " Render graph operation '%s' with resource '%s' must be performed prior to graph execution. " ) , Operation , ResourceName ) ;
}
2020-11-17 17:04:48 -04:00
void FRDGUserValidation : : ValidateCreateResource ( FRDGResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2020-11-17 17:04:48 -04:00
check ( Resource ) ;
2020-11-18 18:25:03 -04:00
Resource - > DebugData = Allocator . Alloc < FRDGResourceDebugData > ( ) ;
2021-04-06 12:38:10 -04:00
bool bAlreadyInSet = false ;
ResourceMap . Emplace ( Resource , & bAlreadyInSet ) ;
check ( ! bAlreadyInSet ) ;
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateCreateParentResource ( FRDGParentResourceRef Resource )
{
ValidateCreateResource ( Resource ) ;
2020-11-18 18:25:03 -04:00
Resource - > ParentDebugData = Allocator . Alloc < FRDGParentResourceDebugData > ( ) ;
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateCreateTexture ( FRDGTextureRef Texture )
{
ValidateCreateParentResource ( Texture ) ;
2020-11-18 18:25:03 -04:00
Texture - > TextureDebugData = Allocator . Alloc < FRDGTextureDebugData > ( ) ;
2020-07-06 18:58:26 -04:00
if ( GRDGDebug )
2019-09-14 09:45:25 -04:00
{
TrackedTextures . Add ( Texture ) ;
}
2019-07-16 13:08:56 -04:00
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : ValidateCreateBuffer ( FRDGBufferRef Buffer )
2019-07-16 13:08:56 -04:00
{
2020-11-17 17:04:48 -04:00
ValidateCreateParentResource ( Buffer ) ;
2020-11-18 18:25:03 -04:00
Buffer - > BufferDebugData = Allocator . Alloc < FRDGBufferDebugData > ( ) ;
2020-07-06 18:58:26 -04:00
if ( GRDGDebug )
2019-09-14 09:45:25 -04:00
{
TrackedBuffers . Add ( Buffer ) ;
}
2019-07-16 13:08:56 -04:00
}
2020-11-17 17:04:48 -04:00
void FRDGUserValidation : : ValidateCreateSRV ( FRDGTextureSRVRef SRV )
2019-09-14 09:45:25 -04:00
{
2020-11-17 17:04:48 -04:00
ValidateCreateResource ( SRV ) ;
2019-09-14 09:45:25 -04:00
}
2020-11-17 17:04:48 -04:00
void FRDGUserValidation : : ValidateCreateSRV ( FRDGBufferSRVRef SRV )
{
ValidateCreateResource ( SRV ) ;
}
void FRDGUserValidation : : ValidateCreateUAV ( FRDGTextureUAVRef UAV )
{
ValidateCreateResource ( UAV ) ;
}
void FRDGUserValidation : : ValidateCreateUAV ( FRDGBufferUAVRef UAV )
{
ValidateCreateResource ( UAV ) ;
}
void FRDGUserValidation : : ValidateCreateUniformBuffer ( FRDGUniformBufferRef UniformBuffer )
{
ValidateCreateResource ( UniformBuffer ) ;
}
void FRDGUserValidation : : ValidateRegisterExternalTexture (
const TRefCountPtr < IPooledRenderTarget > & ExternalPooledTexture ,
const TCHAR * Name ,
ERenderTargetTexture RenderTargetTexture ,
ERDGTextureFlags Flags )
{
checkf ( Name , TEXT ( " Attempted to register external texture with NULL name. " ) ) ;
checkf ( ExternalPooledTexture . IsValid ( ) , TEXT ( " Attempted to register NULL external texture. " ) ) ;
checkf ( ExternalPooledTexture - > IsCompatibleWithRDG ( ) , TEXT ( " Pooled render target %s is not a compatible type for RDG. " ) , Name ) ;
ExecuteGuard ( TEXT ( " RegisterExternalTexture " ) , Name ) ;
}
void FRDGUserValidation : : ValidateRegisterExternalBuffer ( const TRefCountPtr < FRDGPooledBuffer > & ExternalPooledBuffer , const TCHAR * Name , ERDGBufferFlags Flags )
{
checkf ( Name , TEXT ( " Attempted to register external buffer with NULL name. " ) ) ;
checkf ( ExternalPooledBuffer . IsValid ( ) , TEXT ( " Attempted to register NULL external buffer. " ) ) ;
ExecuteGuard ( TEXT ( " RegisterExternalBuffer " ) , Name ) ;
}
void FRDGUserValidation : : ValidateRegisterExternalTexture ( FRDGTextureRef Texture )
{
ValidateCreateTexture ( Texture ) ;
}
void FRDGUserValidation : : ValidateRegisterExternalBuffer ( FRDGBufferRef Buffer )
2019-09-14 09:45:25 -04:00
{
ValidateCreateBuffer ( Buffer ) ;
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateCreateTexture ( const FRDGTextureDesc & Desc , const TCHAR * Name , ERDGTextureFlags Flags )
{
checkf ( Name , TEXT ( " Creating a texture requires a valid debug name. " ) ) ;
ExecuteGuard ( TEXT ( " CreateTexture " ) , Name ) ;
// Validate the pixel format.
checkf ( Desc . Format ! = PF_Unknown , TEXT ( " Illegal to create texture %s with an invalid pixel format. " ) , Name ) ;
checkf ( Desc . Format < PF_MAX , TEXT ( " Illegal to create texture %s with invalid FPooledRenderTargetDesc::Format. " ) , Name ) ;
checkf ( GPixelFormats [ Desc . Format ] . Supported ,
TEXT ( " Failed to create texture %s with pixel format %s because it is not supported. " ) , Name , GPixelFormats [ Desc . Format ] . Name ) ;
checkf ( Desc . IsValid ( ) , TEXT ( " Texture %s was created with an invalid descriptor. " ) , Name ) ;
2021-07-27 15:35:11 -04:00
// Can't create back buffer textures
checkf ( ! EnumHasAnyFlags ( Desc . Flags , ETextureCreateFlags : : Presentable ) , TEXT ( " Illegal to create texture %s with presentable flag. " ) , Name ) ;
2020-11-17 17:04:48 -04:00
2021-05-24 14:25:19 -04:00
const bool bCanHaveUAV = EnumHasAnyFlags ( Desc . Flags , TexCreate_UAV ) ;
2020-11-17 17:04:48 -04:00
const bool bIsMSAA = Desc . NumSamples > 1 ;
// D3D11 doesn't allow creating a UAV on MSAA texture.
const bool bIsUAVForMSAATexture = bIsMSAA & & bCanHaveUAV ;
checkf ( ! bIsUAVForMSAATexture , TEXT ( " TexCreate_UAV is not allowed on MSAA texture %s. " ) , Name ) ;
2020-11-17 18:21:53 -04:00
checkf ( ! EnumHasAnyFlags ( Flags , ERDGTextureFlags : : ReadOnly ) , TEXT ( " Cannot create texture %s with the ReadOnly flag. Only registered textures can use this flag. " ) , Name ) ;
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateCreateBuffer ( const FRDGBufferDesc & Desc , const TCHAR * Name , ERDGBufferFlags Flags )
{
checkf ( Name , TEXT ( " Creating a buffer requires a valid debug name. " ) ) ;
ExecuteGuard ( TEXT ( " CreateBuffer " ) , Name ) ;
checkf ( Desc . GetTotalNumBytes ( ) > 0 , TEXT ( " Creating buffer '%s' is zero bytes in size. " ) , Name ) ;
const bool bIsByteAddress = ( Desc . Usage & BUF_ByteAddressBuffer ) = = BUF_ByteAddressBuffer ;
if ( bIsByteAddress & & Desc . UnderlyingType = = FRDGBufferDesc : : EUnderlyingType : : StructuredBuffer )
{
checkf ( Desc . BytesPerElement = = 4 , TEXT ( " Creating buffer '%s' as a structured buffer that is also byte addressable, BytesPerElement must be 4! Instead it is %d " ) , Name , Desc . BytesPerElement ) ;
}
2020-11-17 18:21:53 -04:00
checkf ( ! EnumHasAnyFlags ( Flags , ERDGBufferFlags : : ReadOnly ) , TEXT ( " Cannot create buffer %s with the ReadOnly flag. Only registered buffers can use this flag. " ) , Name ) ;
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateCreateSRV ( const FRDGTextureSRVDesc & Desc )
{
FRDGTextureRef Texture = Desc . Texture ;
checkf ( Texture , TEXT ( " Texture SRV created with a null texture. " ) ) ;
ExecuteGuard ( TEXT ( " CreateSRV " ) , Texture - > Name ) ;
checkf ( Texture - > Desc . Flags & TexCreate_ShaderResource , TEXT ( " Attempted to create SRV from texture %s which was not created with TexCreate_ShaderResource " ) , Desc . Texture - > Name ) ;
// Validate the pixel format if overridden by the SRV's descriptor.
if ( Desc . Format = = PF_X24_G8 )
{
// PF_X24_G8 is a bit of mess in the RHI, used to read the stencil, but have varying BlockBytes.
checkf ( Texture - > Desc . Format = = PF_DepthStencil , TEXT ( " PF_X24_G8 is only to read stencil from a PF_DepthStencil texture " ) ) ;
}
else if ( Desc . Format ! = PF_Unknown )
{
checkf ( Desc . Format < PF_MAX , TEXT ( " Illegal to create SRV for texture %s with invalid FPooledRenderTargetDesc::Format. " ) , Texture - > Name ) ;
checkf ( GPixelFormats [ Desc . Format ] . Supported , TEXT ( " Failed to create SRV for texture %s with pixel format %s because it is not supported. " ) ,
Texture - > Name , GPixelFormats [ Desc . Format ] . Name ) ;
EPixelFormat ResourcePixelFormat = Texture - > Desc . Format ;
checkf (
GPixelFormats [ Desc . Format ] . BlockBytes = = GPixelFormats [ ResourcePixelFormat ] . BlockBytes & &
GPixelFormats [ Desc . Format ] . BlockSizeX = = GPixelFormats [ ResourcePixelFormat ] . BlockSizeX & &
GPixelFormats [ Desc . Format ] . BlockSizeY = = GPixelFormats [ ResourcePixelFormat ] . BlockSizeY & &
GPixelFormats [ Desc . Format ] . BlockSizeZ = = GPixelFormats [ ResourcePixelFormat ] . BlockSizeZ ,
TEXT ( " Failed to create SRV for texture %s with pixel format %s because it does not match the byte size of the texture's pixel format %s. " ) ,
Texture - > Name , GPixelFormats [ Desc . Format ] . Name , GPixelFormats [ ResourcePixelFormat ] . Name ) ;
}
checkf ( ( Desc . MipLevel + Desc . NumMipLevels ) < = Texture - > Desc . NumMips , TEXT ( " Failed to create SRV at mips %d-%d: the texture %s has only %d mip levels. " ) ,
Desc . MipLevel , ( Desc . MipLevel + Desc . NumMipLevels ) , Texture - > Name , Texture - > Desc . NumMips ) ;
checkf ( Desc . MetaData ! = ERDGTextureMetaDataAccess : : FMask | | GRHISupportsExplicitFMask ,
TEXT ( " Failed to create FMask SRV for texture %s because the current RHI doesn't support it. Be sure to gate the call with GRHISupportsExplicitFMask. " ) ,
Texture - > Name ) ;
checkf ( Desc . MetaData ! = ERDGTextureMetaDataAccess : : HTile | | GRHISupportsExplicitHTile ,
TEXT ( " Failed to create HTile SRV for texture %s because the current RHI doesn't support it. Be sure to gate the call with GRHISupportsExplicitHTile. " ) ,
Texture - > Name ) ;
}
void FRDGUserValidation : : ValidateCreateSRV ( const FRDGBufferSRVDesc & Desc )
{
FRDGBufferRef Buffer = Desc . Buffer ;
checkf ( Buffer , TEXT ( " Buffer SRV created with a null buffer. " ) ) ;
ExecuteGuard ( TEXT ( " CreateSRV " ) , Buffer - > Name ) ;
}
void FRDGUserValidation : : ValidateCreateUAV ( const FRDGTextureUAVDesc & Desc )
{
FRDGTextureRef Texture = Desc . Texture ;
checkf ( Texture , TEXT ( " Texture UAV created with a null texture. " ) ) ;
ExecuteGuard ( TEXT ( " CreateUAV " ) , Texture - > Name ) ;
2021-04-30 11:28:17 -04:00
2021-04-30 13:21:16 -04:00
checkf ( Texture - > Desc . Flags & TexCreate_UAV , TEXT ( " Attempted to create UAV from texture %s which was not created with TexCreate_UAV " ) , Texture - > Name ) ;
2020-11-17 17:04:48 -04:00
checkf ( Desc . MipLevel < Texture - > Desc . NumMips , TEXT ( " Failed to create UAV at mip %d: the texture %s has only %d mip levels. " ) , Desc . MipLevel , Texture - > Name , Texture - > Desc . NumMips ) ;
}
void FRDGUserValidation : : ValidateCreateUAV ( const FRDGBufferUAVDesc & Desc )
{
FRDGBufferRef Buffer = Desc . Buffer ;
checkf ( Buffer , TEXT ( " Buffer UAV created with a null buffer. " ) ) ;
ExecuteGuard ( TEXT ( " CreateUAV " ) , Buffer - > Name ) ;
}
void FRDGUserValidation : : ValidateCreateUniformBuffer ( const void * ParameterStruct , const FShaderParametersMetadata * Metadata )
{
check ( Metadata ) ;
const TCHAR * Name = Metadata - > GetShaderVariableName ( ) ;
checkf ( ParameterStruct , TEXT ( " Uniform buffer '%s' created with null parameters. " ) , Name ) ;
ExecuteGuard ( TEXT ( " CreateUniformBuffer " ) , Name ) ;
}
2021-05-25 20:46:17 -04:00
void FRDGUserValidation : : ValidateUploadBuffer ( FRDGBufferRef Buffer , const void * InitialData , uint64 InitialDataSize )
{
check ( Buffer ) ;
checkf ( ! Buffer - > bQueuedForUpload , TEXT ( " Buffer %s already has an upload queued. Only one upload can be done for each graph. " ) , Buffer - > Name ) ;
check ( InitialData | | InitialDataSize = = 0 ) ;
}
2021-09-01 03:09:25 -04:00
void FRDGUserValidation : : ValidateUploadBuffer ( FRDGBufferRef Buffer , const void * InitialData , uint64 InitialDataSize , const FRDGBufferInitialDataFreeCallback & InitialDataFreeCallback )
{
check ( Buffer ) ;
checkf ( ! Buffer - > bQueuedForUpload , TEXT ( " Buffer %s already has an upload queued. Only one upload can be done for each graph. " ) , Buffer - > Name ) ;
check ( ( InitialData | | InitialDataSize = = 0 ) & & InitialDataFreeCallback ) ;
}
2021-05-25 20:46:17 -04:00
2021-06-07 12:19:06 -04:00
void FRDGUserValidation : : ValidateUploadBuffer ( FRDGBufferRef Buffer , const FRDGBufferInitialDataCallback & InitialDataCallback , const FRDGBufferInitialDataSizeCallback & InitialDataSizeCallback )
{
check ( Buffer ) ;
checkf ( ! Buffer - > bQueuedForUpload , TEXT ( " Buffer %s already has an upload queued. Only one upload can be done for each graph. " ) , Buffer - > Name ) ;
check ( InitialDataCallback & & InitialDataSizeCallback ) ;
}
2021-09-01 03:09:25 -04:00
void FRDGUserValidation : : ValidateUploadBuffer ( FRDGBufferRef Buffer , const FRDGBufferInitialDataCallback & InitialDataCallback , const FRDGBufferInitialDataSizeCallback & InitialDataSizeCallback , const FRDGBufferInitialDataFreeCallback & InitialDataFreeCallback )
{
check ( Buffer ) ;
checkf ( ! Buffer - > bQueuedForUpload , TEXT ( " Buffer %s already has an upload queued. Only one upload can be done for each graph. " ) , Buffer - > Name ) ;
check ( InitialDataCallback & & InitialDataSizeCallback & & InitialDataFreeCallback ) ;
}
2020-11-17 17:04:48 -04:00
void FRDGUserValidation : : ValidateExtractTexture ( FRDGTextureRef Texture , TRefCountPtr < IPooledRenderTarget > * OutTexturePtr )
{
ValidateExtractResource ( Texture ) ;
checkf ( OutTexturePtr , TEXT ( " Texture %s was extracted, but the output texture pointer is null. " ) , Texture - > Name ) ;
}
void FRDGUserValidation : : ValidateExtractBuffer ( FRDGBufferRef Buffer , TRefCountPtr < FRDGPooledBuffer > * OutBufferPtr )
{
ValidateExtractResource ( Buffer ) ;
checkf ( OutBufferPtr , TEXT ( " Texture %s was extracted, but the output texture pointer is null. " ) , Buffer - > Name ) ;
2019-09-14 09:45:25 -04:00
}
void FRDGUserValidation : : ValidateExtractResource ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
check ( Resource ) ;
2021-05-19 17:54:58 -04:00
checkf ( ! bHasExecuteBegun | | ! Resource - > bTransient ,
TEXT ( " Unable to queue the extraction of the resource %s because passes in the graph have already executed and it was made transient. " ) ,
Resource - > Name ) ;
2021-05-25 20:46:17 -04:00
checkf ( Resource - > bProduced | | Resource - > bExternal | | Resource - > bQueuedForUpload ,
2019-07-16 13:08:56 -04:00
TEXT ( " Unable to queue the extraction of the resource %s because it has not been produced by any pass. " ) ,
Resource - > Name ) ;
/** Increment pass access counts for externally registered buffers and textures to avoid
* emitting a ' produced but never used ' warning . We don ' t have the history of registered
* resources to be able to emit a proper warning .
*/
2020-11-17 17:04:48 -04:00
Resource - > GetParentDebugData ( ) . PassAccessCount + + ;
2019-07-16 13:08:56 -04:00
}
2021-05-19 17:54:58 -04:00
void FRDGUserValidation : : ValidateConvertToExternalResource ( FRDGParentResourceRef Resource )
{
check ( Resource ) ;
checkf ( ! bHasExecuteBegun | | ! Resource - > bTransient ,
TEXT ( " Unable to convert resource %s to external because passes in the graph have already executed. " ) ,
Resource - > Name ) ;
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : RemoveUnusedWarning ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
check ( Resource ) ;
2020-11-17 17:04:48 -04:00
ExecuteGuard ( TEXT ( " RemoveUnusedResourceWarning " ) , Resource - > Name ) ;
2019-09-14 09:45:25 -04:00
// Removes 'produced but not used' warning.
2020-11-17 17:04:48 -04:00
Resource - > GetParentDebugData ( ) . PassAccessCount + + ;
2019-09-14 09:45:25 -04:00
// Removes 'not used' warning.
2020-11-17 17:04:48 -04:00
Resource - > GetDebugData ( ) . bIsActuallyUsedByPass = true ;
2020-07-06 18:58:26 -04:00
}
bool FRDGUserValidation : : TryMarkForClobber ( FRDGParentResourceRef Resource ) const
{
2020-11-17 17:04:48 -04:00
check ( Resource ) ;
FRDGParentResourceDebugData & DebugData = Resource - > GetParentDebugData ( ) ;
const bool bClobber = ! DebugData . bHasBeenClobbered & & ! Resource - > bExternal & & IsDebugAllowedForResource ( Resource - > Name ) ;
2020-07-06 18:58:26 -04:00
if ( bClobber )
{
2020-11-17 17:04:48 -04:00
DebugData . bHasBeenClobbered = true ;
2020-07-06 18:58:26 -04:00
}
return bClobber ;
2019-07-16 13:08:56 -04:00
}
2020-11-17 17:04:48 -04:00
void FRDGUserValidation : : ValidateGetPooledTexture ( FRDGTextureRef Texture ) const
{
check ( Texture ) ;
checkf ( Texture - > bExternal , TEXT ( " GetPooledTexture called on texture %s, but it is not external. Call PreallocateTexture or register as an external texture instead. " ) , Texture - > Name ) ;
}
void FRDGUserValidation : : ValidateGetPooledBuffer ( FRDGBufferRef Buffer ) const
{
check ( Buffer ) ;
checkf ( Buffer - > bExternal , TEXT ( " GetPooledBuffer called on buffer %s, but it is not external. Call PreallocateBuffer or register as an external buffer instead. " ) , Buffer - > Name ) ;
}
2021-04-06 11:45:09 -04:00
void FRDGUserValidation : : ValidateSetAccessFinal ( FRDGParentResourceRef Resource , ERHIAccess AccessFinal )
2020-11-17 17:04:48 -04:00
{
2021-04-06 11:45:09 -04:00
check ( Resource ) ;
2020-11-17 17:04:48 -04:00
check ( AccessFinal ! = ERHIAccess : : Unknown & & IsValidAccess ( AccessFinal ) ) ;
2021-04-06 11:45:09 -04:00
checkf ( Resource - > bExternal | | Resource - > bExtracted , TEXT ( " Cannot set final access on non-external resource '%s' unless it is first extracted or preallocated. " ) , Resource - > Name ) ;
checkf ( ! Resource - > bFinalizedAccess , TEXT ( " Cannot set final access on finalized resource %s. " ) , Resource - > Name ) ;
2020-11-17 17:04:48 -04:00
}
2021-04-06 11:45:09 -04:00
void FRDGUserValidation : : ValidateFinalize ( FRDGParentResourceRef Resource , ERHIAccess AccessFinal , FRDGPassHandle FinalizePass )
2020-11-17 17:04:48 -04:00
{
2021-04-06 11:45:09 -04:00
check ( Resource ) ;
2020-11-17 17:04:48 -04:00
check ( AccessFinal ! = ERHIAccess : : Unknown & & IsValidAccess ( AccessFinal ) ) ;
2021-04-06 11:45:09 -04:00
checkf ( IsReadOnlyAccess ( AccessFinal ) , TEXT ( " Cannot convert resource %s to untracked with access %s. Access must be read-only. " ) , Resource - > Name , * GetRHIAccessName ( AccessFinal ) ) ;
checkf ( Resource - > bExternal | | Resource - > bExtracted , TEXT ( " Cannot convert resource %s to untracked unless it is first extracted or made external. " ) , Resource - > Name ) ;
Resource - > GetParentDebugData ( ) . FinalizePass = FinalizePass ;
}
void FRDGUserValidation : : ValidateFinalizedAccess ( FRDGParentResourceRef Resource , ERHIAccess Access , const FRDGPass * Pass )
{
ensureMsgf ( EnumHasAnyFlags ( Resource - > AccessFinal , Access ) ,
TEXT ( " Resource %s was finalized with access %s, but is being used in pass %s with access %s. Any future pass must use a subset of the finalized access state. " ) ,
Resource - > Name , * GetRHIAccessName ( Resource - > AccessFinal ) , Pass - > GetName ( ) , * GetRHIAccessName ( Access ) , * GetRHIPipelineName ( Pass - > GetPipeline ( ) ) ) ;
2021-06-01 13:22:44 -04:00
#if 0 // TODO: Need to account for read-only resources.
2021-04-06 11:45:09 -04:00
ensureMsgf ( Pass - > GetPipeline ( ) = = ERHIPipeline : : Graphics ,
TEXT ( " Resource %s was finalized but is being used on the async compute pass %s. Only graphics pipe access is allowed for finalized resources. " ) ,
Resource - > Name , Pass - > GetName ( ) ) ;
2021-06-01 13:22:44 -04:00
# endif
2020-11-17 17:04:48 -04:00
}
void FRDGUserValidation : : ValidateAddPass ( const FRDGEventName & Name , ERDGPassFlags Flags )
{
ExecuteGuard ( TEXT ( " AddPass " ) , Name . GetTCHAR ( ) ) ;
checkf ( ! EnumHasAnyFlags ( Flags , ERDGPassFlags : : Copy | ERDGPassFlags : : Compute | ERDGPassFlags : : AsyncCompute | ERDGPassFlags : : Raster ) ,
TEXT ( " Pass %s may not specify any of the (Copy, Compute, AsyncCompute, Raster) flags, because it has no parameters. Use None instead. " ) , Name . GetTCHAR ( ) ) ;
}
void FRDGUserValidation : : ValidateAddPass ( const void * ParameterStruct , const FShaderParametersMetadata * Metadata , const FRDGEventName & Name , ERDGPassFlags Flags )
{
checkf ( ParameterStruct , TEXT ( " Pass '%s' created with null parameters. " ) , Name . GetTCHAR ( ) ) ;
ExecuteGuard ( TEXT ( " AddPass " ) , Name . GetTCHAR ( ) ) ;
2021-02-18 20:06:45 -04:00
checkf ( EnumHasAnyFlags ( Flags , ERDGPassFlags : : Raster | ERDGPassFlags : : Compute | ERDGPassFlags : : AsyncCompute | ERDGPassFlags : : Copy ) ,
2020-11-17 17:04:48 -04:00
TEXT ( " Pass %s must specify at least one of the following flags: (Copy, Compute, AsyncCompute, Raster) " ) , Name . GetTCHAR ( ) ) ;
checkf ( ! EnumHasAllFlags ( Flags , ERDGPassFlags : : Compute | ERDGPassFlags : : AsyncCompute ) ,
TEXT ( " Pass %s specified both Compute and AsyncCompute. They are mutually exclusive. " ) , Name . GetTCHAR ( ) ) ;
checkf ( ! EnumHasAllFlags ( Flags , ERDGPassFlags : : Raster | ERDGPassFlags : : AsyncCompute ) ,
TEXT ( " Pass %s specified both Raster and AsyncCompute. They are mutually exclusive. " ) , Name . GetTCHAR ( ) ) ;
checkf ( ! EnumHasAllFlags ( Flags , ERDGPassFlags : : SkipRenderPass ) | | EnumHasAllFlags ( Flags , ERDGPassFlags : : Raster ) ,
TEXT ( " Pass %s specified SkipRenderPass without Raster. Only raster passes support this flag. " ) ) ;
2021-04-12 15:36:14 -04:00
checkf ( ! EnumHasAllFlags ( Flags , ERDGPassFlags : : NeverMerge ) | | EnumHasAllFlags ( Flags , ERDGPassFlags : : Raster ) ,
TEXT ( " Pass %s specified NeverMerge without Raster. Only raster passes support this flag. " ) ) ;
2020-11-17 17:04:48 -04:00
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : ValidateAddPass ( const FRDGPass * Pass , bool bSkipPassAccessMarking )
2019-07-16 13:08:56 -04:00
{
const FRenderTargetBindingSlots * RenderTargetBindingSlots = nullptr ;
2020-07-06 18:58:26 -04:00
// Pass flags are validated as early as possible by the builder in AddPass.
const ERDGPassFlags PassFlags = Pass - > GetFlags ( ) ;
2020-09-24 00:43:27 -04:00
const FRDGParameterStruct PassParameters = Pass - > GetParameters ( ) ;
2019-07-16 13:08:56 -04:00
const TCHAR * PassName = Pass - > GetName ( ) ;
2020-07-06 18:58:26 -04:00
const bool bIsRaster = EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Raster ) ;
const bool bIsCopy = EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Copy ) ;
2020-09-24 00:43:27 -04:00
const bool bIsAnyCompute = EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Compute | ERDGPassFlags : : AsyncCompute ) ;
const bool bSkipRenderPass = EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : SkipRenderPass ) ;
2019-09-14 09:45:25 -04:00
2020-11-17 18:21:53 -04:00
const auto MarkAsProduced = [ & ] ( FRDGParentResourceRef Resource )
2019-09-14 09:45:25 -04:00
{
2020-07-06 18:58:26 -04:00
if ( ! bSkipPassAccessMarking )
2019-09-14 09:45:25 -04:00
{
2020-11-17 17:04:48 -04:00
auto & Debug = Resource - > GetParentDebugData ( ) ;
if ( ! Debug . FirstProducer )
2020-07-06 18:58:26 -04:00
{
Debug . FirstProducer = Pass ;
}
Debug . PassAccessCount + + ;
2019-09-14 09:45:25 -04:00
}
2020-07-06 18:58:26 -04:00
} ;
2019-07-16 13:08:56 -04:00
2020-11-17 18:21:53 -04:00
const auto MarkTextureAsProduced = [ & ] ( FRDGTextureRef Texture )
{
checkf ( ! EnumHasAnyFlags ( Texture - > Flags , ERDGTextureFlags : : ReadOnly ) , TEXT ( " Pass %s is attempting to write to texture %s which is marked as ReadOnly. " ) , Pass - > GetName ( ) , Texture - > Name ) ;
MarkAsProduced ( Texture ) ;
} ;
const auto MarkBufferAsProduced = [ & ] ( FRDGBufferRef Buffer )
{
checkf ( ! EnumHasAnyFlags ( Buffer - > Flags , ERDGBufferFlags : : ReadOnly ) , TEXT ( " Pass %s is attempting to write to buffer %s which is marked as ReadOnly. " ) , Pass - > GetName ( ) , Buffer - > Name ) ;
MarkAsProduced ( Buffer ) ;
} ;
2020-07-06 18:58:26 -04:00
const auto MarkAsConsumed = [ & ] ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2021-05-25 20:46:17 -04:00
ensureMsgf ( Resource - > bProduced | | Resource - > bExternal | | Resource - > bQueuedForUpload ,
2020-07-06 18:58:26 -04:00
TEXT ( " Pass %s has a read dependency on %s, but it was never written to. " ) ,
PassName , Resource - > Name ) ;
if ( ! bSkipPassAccessMarking )
{
2020-11-17 17:04:48 -04:00
Resource - > GetParentDebugData ( ) . PassAccessCount + + ;
2020-07-06 18:58:26 -04:00
}
} ;
2021-04-06 12:38:10 -04:00
const auto CheckValidResource = [ & ] ( FRDGResourceRef Resource )
2020-09-24 00:43:27 -04:00
{
2021-04-06 12:38:10 -04:00
checkf ( ResourceMap . Contains ( Resource ) , TEXT ( " Resource at %p registered with pass %s is not part of the graph and is likely a dangling pointer or garbage value. " ) , Resource , Pass - > GetName ( ) ) ;
2020-09-24 00:43:27 -04:00
} ;
2020-07-06 18:58:26 -04:00
const auto CheckNotCopy = [ & ] ( FRDGResourceRef Resource )
{
ensureMsgf ( ! bIsCopy , TEXT ( " Pass %s, parameter %s is valid for Raster or (Async)Compute, but the pass is a Copy pass. " ) , PassName , Resource - > Name ) ;
} ;
2020-09-24 00:43:27 -04:00
bool bCanProduce = false ;
2020-07-06 18:58:26 -04:00
2021-04-02 20:35:50 -04:00
const auto CheckResourceAccess = [ & ] ( FRDGParentResourceRef Resource , ERHIAccess Access )
{
checkf ( bIsCopy | | ! EnumHasAnyFlags ( Access , AccessMaskCopy ) , TEXT ( " Pass '%s' uses resource '%s' with access '%s' containing states which require the 'ERDGPass::Copy' flag. " ) , Pass - > GetName ( ) , Resource - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsAnyCompute | | ! EnumHasAnyFlags ( Access , AccessMaskCompute ) , TEXT ( " Pass '%s' uses resource '%s' with access '%s' containing states which require the 'ERDGPass::Compute' or 'ERDGPassFlags::AsyncCompute' flag. " ) , Pass - > GetName ( ) , Resource - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskRaster ) , TEXT ( " Pass '%s' uses resource '%s' with access '%s' containing states which require the 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Resource - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsAnyCompute | | bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskComputeOrRaster ) , TEXT ( " Pass '%s' uses resource '%s' with access '%s' containing states which require the 'ERDGPassFlags::Compute' or 'ERDGPassFlags::AsyncCompute' or 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Resource - > Name , * GetRHIAccessName ( Access ) ) ;
} ;
const auto CheckBufferAccess = [ & ] ( FRDGBufferRef Buffer , ERHIAccess Access )
{
CheckResourceAccess ( Buffer , Access ) ;
if ( IsWritableAccess ( Access ) )
{
MarkBufferAsProduced ( Buffer ) ;
2021-04-06 11:45:09 -04:00
bCanProduce = true ;
2021-04-02 20:35:50 -04:00
}
} ;
const auto CheckTextureAccess = [ & ] ( FRDGTextureRef Texture , ERHIAccess Access )
{
CheckResourceAccess ( Texture , Access ) ;
if ( IsWritableAccess ( Access ) )
{
MarkTextureAsProduced ( Texture ) ;
2021-04-06 11:45:09 -04:00
bCanProduce = true ;
2021-04-02 20:35:50 -04:00
}
} ;
2020-09-24 00:43:27 -04:00
PassParameters . Enumerate ( [ & ] ( FRDGParameter Parameter )
2020-07-06 18:58:26 -04:00
{
2021-04-06 12:38:10 -04:00
if ( Parameter . IsResource ( ) )
2020-09-24 00:43:27 -04:00
{
2021-04-06 12:38:10 -04:00
if ( FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
2020-09-24 00:43:27 -04:00
{
2021-04-06 12:38:10 -04:00
CheckValidResource ( Resource ) ;
2020-09-24 00:43:27 -04:00
}
}
2019-07-16 13:08:56 -04:00
switch ( Parameter . GetType ( ) )
{
case UBMT_RDG_TEXTURE :
{
if ( FRDGTextureRef Texture = Parameter . GetAsTexture ( ) )
{
2019-09-14 09:45:25 -04:00
MarkAsConsumed ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RDG_TEXTURE_SRV :
{
if ( FRDGTextureSRVRef SRV = Parameter . GetAsTextureSRV ( ) )
{
2019-09-14 09:45:25 -04:00
FRDGTextureRef Texture = SRV - > GetParent ( ) ;
2020-07-06 18:58:26 -04:00
CheckNotCopy ( Texture ) ;
2019-09-14 09:45:25 -04:00
MarkAsConsumed ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RDG_TEXTURE_UAV :
{
2020-09-24 00:43:27 -04:00
bCanProduce = true ;
2019-07-16 13:08:56 -04:00
if ( FRDGTextureUAVRef UAV = Parameter . GetAsTextureUAV ( ) )
{
2019-09-14 09:45:25 -04:00
FRDGTextureRef Texture = UAV - > GetParent ( ) ;
2020-07-06 18:58:26 -04:00
CheckNotCopy ( Texture ) ;
2020-11-17 18:21:53 -04:00
MarkTextureAsProduced ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RDG_BUFFER_SRV :
{
if ( FRDGBufferSRVRef SRV = Parameter . GetAsBufferSRV ( ) )
{
2019-09-14 09:45:25 -04:00
FRDGBufferRef Buffer = SRV - > GetParent ( ) ;
2020-07-06 18:58:26 -04:00
CheckNotCopy ( Buffer ) ;
2019-09-14 09:45:25 -04:00
MarkAsConsumed ( Buffer ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RDG_BUFFER_UAV :
{
2020-09-24 00:43:27 -04:00
bCanProduce = true ;
2019-07-16 13:08:56 -04:00
if ( FRDGBufferUAVRef UAV = Parameter . GetAsBufferUAV ( ) )
{
2019-09-14 09:45:25 -04:00
FRDGBufferRef Buffer = UAV - > GetParent ( ) ;
2020-07-06 18:58:26 -04:00
CheckNotCopy ( Buffer ) ;
2020-11-17 18:21:53 -04:00
MarkBufferAsProduced ( Buffer ) ;
2019-09-14 09:45:25 -04:00
}
}
break ;
2020-09-24 00:43:27 -04:00
case UBMT_RDG_TEXTURE_ACCESS :
2019-09-14 09:45:25 -04:00
{
2021-04-02 20:35:50 -04:00
FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) ;
bCanProduce | = IsWritableAccess ( TextureAccess . GetAccess ( ) ) ;
2020-09-24 00:43:27 -04:00
2021-04-02 20:35:50 -04:00
if ( TextureAccess )
2019-09-14 09:45:25 -04:00
{
2021-04-02 20:35:50 -04:00
CheckTextureAccess ( TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) ) ;
}
}
break ;
case UBMT_RDG_TEXTURE_ACCESS_ARRAY :
{
const FRDGTextureAccessArray & TextureAccessArray = Parameter . GetAsTextureAccessArray ( ) ;
2020-09-24 00:43:27 -04:00
2021-04-06 11:45:09 -04:00
for ( FRDGTextureAccess TextureAccess : TextureAccessArray )
2021-04-02 20:35:50 -04:00
{
2021-04-06 11:45:09 -04:00
CheckTextureAccess ( TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) ) ;
2019-09-14 09:45:25 -04:00
}
}
break ;
2020-09-24 00:43:27 -04:00
case UBMT_RDG_BUFFER_ACCESS :
2019-09-14 09:45:25 -04:00
{
2021-04-02 20:35:50 -04:00
FRDGBufferAccess BufferAccess = Parameter . GetAsBufferAccess ( ) ;
2020-09-24 00:43:27 -04:00
2021-04-02 20:35:50 -04:00
if ( BufferAccess )
2019-09-14 09:45:25 -04:00
{
2021-04-02 20:35:50 -04:00
CheckBufferAccess ( BufferAccess . GetBuffer ( ) , BufferAccess . GetAccess ( ) ) ;
}
}
break ;
case UBMT_RDG_BUFFER_ACCESS_ARRAY :
{
const FRDGBufferAccessArray & BufferAccessArray = Parameter . GetAsBufferAccessArray ( ) ;
2020-09-24 00:43:27 -04:00
2021-04-06 11:45:09 -04:00
for ( FRDGBufferAccess BufferAccess : BufferAccessArray )
2021-04-02 20:35:50 -04:00
{
2021-04-06 11:45:09 -04:00
CheckBufferAccess ( BufferAccess . GetBuffer ( ) , BufferAccess . GetAccess ( ) ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RENDER_TARGET_BINDING_SLOTS :
{
2020-07-06 18:58:26 -04:00
RenderTargetBindingSlots = & Parameter . GetAsRenderTargetBindingSlots ( ) ;
2020-09-24 00:43:27 -04:00
bCanProduce = true ;
2019-07-16 13:08:56 -04:00
}
break ;
}
2020-09-24 00:43:27 -04:00
} ) ;
checkf ( bCanProduce | | EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : NeverCull ) | | PassParameters . HasExternalOutputs ( ) ,
TEXT ( " Pass '%s' has no graph parameters defined on its parameter struct and did not specify 'NeverCull'. The pass will always be culled. " ) , PassName ) ;
2019-07-16 13:08:56 -04:00
/** Validate that raster passes have render target binding slots and compute passes don't. */
if ( RenderTargetBindingSlots )
{
2020-07-06 18:58:26 -04:00
checkf ( bIsRaster , TEXT ( " Pass '%s' has render target binding slots but is not set to 'Raster'. " ) , PassName ) ;
2019-07-16 13:08:56 -04:00
}
else
{
2020-09-24 00:43:27 -04:00
checkf ( ! bIsRaster | | bSkipRenderPass , TEXT ( " Pass '%s' is set to 'Raster' but is missing render target binding slots. Use 'SkipRenderPass' if this is desired. " ) , PassName ) ;
2019-07-16 13:08:56 -04:00
}
/** Validate render target / depth stencil binding usage. */
if ( RenderTargetBindingSlots )
{
const auto & RenderTargets = RenderTargetBindingSlots - > Output ;
{
2021-03-05 18:33:15 -04:00
if ( FRDGTextureRef Texture = RenderTargetBindingSlots - > ShadingRateTexture )
2021-03-05 16:16:14 -04:00
{
2021-04-06 12:38:10 -04:00
CheckValidResource ( Texture ) ;
2021-03-05 16:16:14 -04:00
MarkAsConsumed ( Texture ) ;
}
2019-07-16 13:08:56 -04:00
const auto & DepthStencil = RenderTargetBindingSlots - > DepthStencil ;
2020-09-24 00:43:27 -04:00
const auto CheckDepthStencil = [ & ] ( FRDGTextureRef Texture )
2019-07-16 13:08:56 -04:00
{
// Depth stencil only supports one mip, since there isn't actually a way to select the mip level.
check ( Texture - > Desc . NumMips = = 1 ) ;
2021-04-06 12:38:10 -04:00
CheckValidResource ( Texture ) ;
2019-07-16 13:08:56 -04:00
if ( DepthStencil . GetDepthStencilAccess ( ) . IsAnyWrite ( ) )
{
2020-11-17 18:21:53 -04:00
MarkTextureAsProduced ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
else
{
2019-09-14 09:45:25 -04:00
MarkAsConsumed ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
2020-09-24 00:43:27 -04:00
} ;
FRDGTextureRef Texture = DepthStencil . GetTexture ( ) ;
if ( Texture )
{
checkf (
EnumHasAnyFlags ( Texture - > Desc . Flags , TexCreate_DepthStencilTargetable | TexCreate_DepthStencilResolveTarget ) ,
TEXT ( " Pass '%s' attempted to bind texture '%s' as a depth stencil render target, but the texture has not been created with TexCreate_DepthStencilTargetable. " ) ,
PassName , Texture - > Name ) ;
CheckDepthStencil ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
}
const uint32 RenderTargetCount = RenderTargets . Num ( ) ;
{
/** Tracks the number of contiguous, non-null textures in the render target output array. */
2021-06-22 00:27:54 -04:00
uint32 ValidRenderTargetCount = RenderTargetCount ;
2019-07-16 13:08:56 -04:00
for ( uint32 RenderTargetIndex = 0 ; RenderTargetIndex < RenderTargetCount ; + + RenderTargetIndex )
{
const FRenderTargetBinding & RenderTarget = RenderTargets [ RenderTargetIndex ] ;
2020-09-24 00:43:27 -04:00
FRDGTextureRef Texture = RenderTarget . GetTexture ( ) ;
FRDGTextureRef ResolveTexture = RenderTarget . GetResolveTexture ( ) ;
if ( ResolveTexture & & ResolveTexture ! = Texture )
2019-07-16 13:08:56 -04:00
{
2020-09-24 00:43:27 -04:00
checkf ( RenderTarget . GetTexture ( ) , TEXT ( " Pass %s specified resolve target '%s' with a null render target. " ) , PassName , ResolveTexture - > Name ) ;
2019-07-23 17:49:47 -04:00
ensureMsgf (
2020-09-24 00:43:27 -04:00
EnumHasAnyFlags ( ResolveTexture - > Desc . Flags , TexCreate_ResolveTargetable ) ,
TEXT ( " Pass '%s' attempted to bind texture '%s' as a render target, but the texture has not been created with TexCreate_ResolveTargetable. " ) ,
PassName , ResolveTexture - > Name ) ;
2021-04-06 12:38:10 -04:00
CheckValidResource ( Texture ) ;
2020-11-17 18:21:53 -04:00
MarkTextureAsProduced ( ResolveTexture ) ;
2020-09-24 00:43:27 -04:00
}
if ( Texture )
{
ensureMsgf (
EnumHasAnyFlags ( Texture - > Desc . Flags , TexCreate_RenderTargetable | TexCreate_ResolveTargetable ) ,
2019-07-23 17:49:47 -04:00
TEXT ( " Pass '%s' attempted to bind texture '%s' as a render target, but the texture has not been created with TexCreate_RenderTargetable. " ) ,
PassName , Texture - > Name ) ;
2021-04-06 12:38:10 -04:00
CheckValidResource ( Texture ) ;
2019-07-23 17:49:47 -04:00
2019-07-16 13:08:56 -04:00
/** Mark the pass as a producer for render targets with a store action. */
2020-11-17 18:21:53 -04:00
MarkTextureAsProduced ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
else
{
/** Found end of contiguous interval of valid render targets. */
ValidRenderTargetCount = RenderTargetIndex ;
break ;
}
}
/** Validate that no holes exist in the render target output array. Render targets must be bound contiguously. */
for ( uint32 RenderTargetIndex = ValidRenderTargetCount ; RenderTargetIndex < RenderTargetCount ; + + RenderTargetIndex )
{
const FRenderTargetBinding & RenderTarget = RenderTargets [ RenderTargetIndex ] ;
2020-09-24 00:43:27 -04:00
checkf ( RenderTarget . GetTexture ( ) = = nullptr & & RenderTarget . GetResolveTexture ( ) = = nullptr , TEXT ( " Render targets must be packed. No empty spaces in the array. " ) ) ;
2019-07-16 13:08:56 -04:00
}
}
}
}
void FRDGUserValidation : : ValidateExecuteBegin ( )
{
checkf ( ! bHasExecuted , TEXT ( " Render graph execution should only happen once to ensure consistency with immediate mode. " ) ) ;
2021-05-19 17:54:58 -04:00
check ( ! bHasExecuteBegun ) ;
bHasExecuteBegun = true ;
2019-07-16 13:08:56 -04:00
}
void FRDGUserValidation : : ValidateExecuteEnd ( )
{
2021-05-19 17:54:58 -04:00
check ( bHasExecuteBegun ) ;
2020-10-23 16:26:52 -04:00
2019-07-16 13:08:56 -04:00
bHasExecuted = true ;
2021-07-13 12:38:37 -04:00
GRDGBuilderActive = false ;
2019-07-16 13:08:56 -04:00
2020-07-06 18:58:26 -04:00
if ( GRDGDebug )
2019-07-16 13:08:56 -04:00
{
2019-09-14 09:45:25 -04:00
auto ValidateResourceAtExecuteEnd = [ ] ( const FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2021-08-26 14:06:40 -04:00
check ( Resource - > ReferenceCount = = Resource - > bExtracted ? 1 : 0 ) ;
2019-07-16 13:08:56 -04:00
2020-11-17 17:04:48 -04:00
const auto & ParentDebugData = Resource - > GetParentDebugData ( ) ;
2020-07-06 18:58:26 -04:00
const bool bProducedButNeverUsed = ParentDebugData . PassAccessCount = = 1 & & ParentDebugData . FirstProducer ;
2019-09-14 09:45:25 -04:00
if ( bProducedButNeverUsed )
{
2020-11-30 13:16:32 -04:00
check ( Resource - > bProduced | | Resource - > bExternal | | Resource - > bExtracted ) ;
2019-09-14 09:45:25 -04:00
EmitRDGWarningf (
TEXT ( " Resource %s has been produced by the pass %s, but never used by another pass. " ) ,
2020-07-06 18:58:26 -04:00
Resource - > Name , ParentDebugData . FirstProducer - > GetName ( ) ) ;
2019-09-14 09:45:25 -04:00
}
} ;
for ( const FRDGTextureRef Texture : TrackedTextures )
{
ValidateResourceAtExecuteEnd ( Texture ) ;
2020-11-17 17:04:48 -04:00
const auto & ParentDebugData = Texture - > GetParentDebugData ( ) ;
const auto & TextureDebugData = Texture - > GetTextureDebugData ( ) ;
2019-09-14 09:45:25 -04:00
2020-11-17 17:04:48 -04:00
const bool bHasBeenProducedByGraph = ! Texture - > bExternal & & ParentDebugData . PassAccessCount > 0 ;
if ( bHasBeenProducedByGraph & & ! TextureDebugData . bHasNeededUAV & & EnumHasAnyFlags ( Texture - > Desc . Flags , TexCreate_UAV ) )
2019-09-14 09:45:25 -04:00
{
EmitRDGWarningf (
TEXT ( " Resource %s first produced by the pass %s had the TexCreate_UAV flag, but no UAV has been used. " ) ,
2020-11-17 17:04:48 -04:00
Texture - > Name , ParentDebugData . FirstProducer - > GetName ( ) ) ;
2019-09-14 09:45:25 -04:00
}
2020-11-17 17:04:48 -04:00
if ( bHasBeenProducedByGraph & & ! TextureDebugData . bHasBeenBoundAsRenderTarget & & EnumHasAnyFlags ( Texture - > Desc . Flags , TexCreate_RenderTargetable ) )
2019-09-14 09:45:25 -04:00
{
EmitRDGWarningf (
TEXT ( " Resource %s first produced by the pass %s had the TexCreate_RenderTargetable flag, but has never been bound as a render target of a pass. " ) ,
2020-11-17 17:04:48 -04:00
Texture - > Name , ParentDebugData . FirstProducer - > GetName ( ) ) ;
2019-09-14 09:45:25 -04:00
}
}
for ( const FRDGBufferRef Buffer : TrackedBuffers )
{
ValidateResourceAtExecuteEnd ( Buffer ) ;
2019-07-16 13:08:56 -04:00
}
}
2019-09-14 09:45:25 -04:00
TrackedTextures . Empty ( ) ;
TrackedBuffers . Empty ( ) ;
2019-07-16 13:08:56 -04:00
}
void FRDGUserValidation : : ValidateExecutePassBegin ( const FRDGPass * Pass )
{
2021-07-29 13:02:16 -04:00
if ( bParallelExecuteEnabled )
2021-07-13 12:38:37 -04:00
{
return ;
}
2019-09-14 09:45:25 -04:00
2019-07-16 13:08:56 -04:00
SetAllowRHIAccess ( Pass , true ) ;
2019-09-14 09:45:25 -04:00
2020-07-06 18:58:26 -04:00
if ( GRDGDebug )
2019-09-14 09:45:25 -04:00
{
2020-12-07 17:42:32 -04:00
Pass - > GetParameters ( ) . EnumerateUniformBuffers ( [ & ] ( FRDGUniformBufferBinding UniformBuffer )
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
// Global uniform buffers are always marked as used, because FShader traversal doesn't know about them.
2020-12-07 17:42:32 -04:00
if ( UniformBuffer . IsStatic ( ) )
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
UniformBuffer - > MarkResourceAsUsed ( ) ;
}
} ) ;
2021-04-02 20:35:50 -04:00
const auto ValidateTextureAccess = [ ] ( FRDGTextureRef Texture , ERHIAccess Access )
{
if ( EnumHasAnyFlags ( Access , ERHIAccess : : UAVMask ) )
{
Texture - > GetTextureDebugData ( ) . bHasNeededUAV = true ;
}
if ( EnumHasAnyFlags ( Access , ERHIAccess : : RTV | ERHIAccess : : DSVRead | ERHIAccess : : DSVWrite ) )
{
Texture - > GetTextureDebugData ( ) . bHasBeenBoundAsRenderTarget = true ;
}
Texture - > MarkResourceAsUsed ( ) ;
} ;
2020-09-24 00:43:27 -04:00
Pass - > GetParameters ( ) . Enumerate ( [ & ] ( FRDGParameter Parameter )
{
switch ( Parameter . GetType ( ) )
{
case UBMT_RDG_TEXTURE_UAV :
2019-09-14 09:45:25 -04:00
if ( FRDGTextureUAVRef UAV = Parameter . GetAsTextureUAV ( ) )
{
FRDGTextureRef Texture = UAV - > Desc . Texture ;
2020-11-17 17:04:48 -04:00
Texture - > GetTextureDebugData ( ) . bHasNeededUAV = true ;
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
break ;
case UBMT_RDG_TEXTURE_ACCESS :
2021-04-02 20:35:50 -04:00
if ( FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) )
2020-09-24 00:43:27 -04:00
{
2021-04-02 20:35:50 -04:00
ValidateTextureAccess ( TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) ) ;
}
break ;
case UBMT_RDG_TEXTURE_ACCESS_ARRAY :
{
const FRDGTextureAccessArray & TextureAccessArray = Parameter . GetAsTextureAccessArray ( ) ;
2021-04-06 11:45:09 -04:00
for ( FRDGTextureAccess TextureAccess : TextureAccessArray )
2021-04-02 20:35:50 -04:00
{
2021-04-06 11:45:09 -04:00
ValidateTextureAccess ( TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) ) ;
2020-10-26 12:05:19 -04:00
}
}
break ;
case UBMT_RDG_BUFFER_ACCESS :
if ( FRDGBufferRef Buffer = Parameter . GetAsBuffer ( ) )
{
Buffer - > MarkResourceAsUsed ( ) ;
2020-09-24 00:43:27 -04:00
}
break ;
2021-04-02 20:35:50 -04:00
case UBMT_RDG_BUFFER_ACCESS_ARRAY :
2021-04-06 11:45:09 -04:00
for ( FRDGBufferAccess BufferAccess : Parameter . GetAsBufferAccessArray ( ) )
2021-04-02 20:35:50 -04:00
{
2021-04-06 11:45:09 -04:00
BufferAccess - > MarkResourceAsUsed ( ) ;
2021-04-02 20:35:50 -04:00
}
break ;
2020-09-24 00:43:27 -04:00
case UBMT_RENDER_TARGET_BINDING_SLOTS :
2019-09-14 09:45:25 -04:00
{
2020-07-06 18:58:26 -04:00
const FRenderTargetBindingSlots & RenderTargets = Parameter . GetAsRenderTargetBindingSlots ( ) ;
2019-09-14 09:45:25 -04:00
2020-07-06 18:58:26 -04:00
RenderTargets . Enumerate ( [ & ] ( FRenderTargetBinding RenderTarget )
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGTextureRef Texture = RenderTarget . GetTexture ( ) ;
2020-11-17 17:04:48 -04:00
Texture - > GetTextureDebugData ( ) . bHasBeenBoundAsRenderTarget = true ;
2020-09-24 00:43:27 -04:00
Texture - > MarkResourceAsUsed ( ) ;
2020-07-06 18:58:26 -04:00
} ) ;
2019-09-14 09:45:25 -04:00
2020-07-06 18:58:26 -04:00
if ( FRDGTextureRef Texture = RenderTargets . DepthStencil . GetTexture ( ) )
2019-09-14 09:45:25 -04:00
{
2020-11-17 17:04:48 -04:00
Texture - > GetTextureDebugData ( ) . bHasBeenBoundAsRenderTarget = true ;
2020-09-24 00:43:27 -04:00
Texture - > MarkResourceAsUsed ( ) ;
2019-09-14 09:45:25 -04:00
}
2021-03-05 16:16:14 -04:00
2021-03-05 18:33:15 -04:00
if ( FRDGTextureRef Texture = RenderTargets . ShadingRateTexture )
2021-03-05 16:16:14 -04:00
{
Texture - > MarkResourceAsUsed ( ) ;
2021-03-17 12:44:59 -04:00
}
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
break ;
}
} ) ;
2020-07-06 18:58:26 -04:00
}
2019-07-16 13:08:56 -04:00
}
void FRDGUserValidation : : ValidateExecutePassEnd ( const FRDGPass * Pass )
{
2021-07-29 13:02:16 -04:00
if ( bParallelExecuteEnabled )
2021-07-13 12:38:37 -04:00
{
return ;
}
2019-07-16 13:08:56 -04:00
SetAllowRHIAccess ( Pass , false ) ;
2020-09-24 00:43:27 -04:00
const FRDGParameterStruct PassParameters = Pass - > GetParameters ( ) ;
2019-07-16 13:08:56 -04:00
2020-07-06 18:58:26 -04:00
if ( GRDGDebug )
2019-07-16 13:08:56 -04:00
{
uint32 TrackedResourceCount = 0 ;
uint32 UsedResourceCount = 0 ;
2020-09-24 00:43:27 -04:00
PassParameters . Enumerate ( [ & ] ( FRDGParameter Parameter )
2019-07-16 13:08:56 -04:00
{
if ( Parameter . IsResource ( ) )
{
if ( FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
{
TrackedResourceCount + + ;
2020-11-17 17:04:48 -04:00
UsedResourceCount + = Resource - > GetDebugData ( ) . bIsActuallyUsedByPass ? 1 : 0 ;
2019-07-16 13:08:56 -04:00
}
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-07-16 13:08:56 -04:00
if ( TrackedResourceCount ! = UsedResourceCount )
{
FString WarningMessage = FString : : Printf (
2019-09-14 09:45:25 -04:00
TEXT ( " '%d' of the '%d' resources of the pass '%s' were not actually used. " ) ,
2019-07-16 13:08:56 -04:00
TrackedResourceCount - UsedResourceCount , TrackedResourceCount , Pass - > GetName ( ) ) ;
2020-09-24 00:43:27 -04:00
PassParameters . Enumerate ( [ & ] ( FRDGParameter Parameter )
2019-07-16 13:08:56 -04:00
{
if ( Parameter . IsResource ( ) )
{
if ( const FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
{
2020-11-17 17:04:48 -04:00
if ( ! Resource - > GetDebugData ( ) . bIsActuallyUsedByPass )
2019-07-16 13:08:56 -04:00
{
WarningMessage + = FString : : Printf ( TEXT ( " \n %s " ) , Resource - > Name ) ;
}
}
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-07-16 13:08:56 -04:00
EmitRDGWarning ( WarningMessage ) ;
}
}
2020-09-24 00:43:27 -04:00
PassParameters . Enumerate ( [ & ] ( FRDGParameter Parameter )
2019-07-16 13:08:56 -04:00
{
if ( Parameter . IsResource ( ) )
{
2020-07-06 18:58:26 -04:00
if ( FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
2019-07-16 13:08:56 -04:00
{
2020-11-17 17:04:48 -04:00
Resource - > GetDebugData ( ) . bIsActuallyUsedByPass = false ;
2019-07-16 13:08:56 -04:00
}
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-07-16 13:08:56 -04:00
}
void FRDGUserValidation : : SetAllowRHIAccess ( const FRDGPass * Pass , bool bAllowAccess )
{
2020-09-24 00:43:27 -04:00
Pass - > GetParameters ( ) . Enumerate ( [ & ] ( FRDGParameter Parameter )
2019-07-16 13:08:56 -04:00
{
if ( Parameter . IsResource ( ) )
{
if ( FRDGResourceRef Resource = Parameter . GetAsResource ( ) )
{
2020-11-17 17:04:48 -04:00
Resource - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
2019-07-16 13:08:56 -04:00
}
}
2021-05-04 11:53:08 -04:00
else if ( Parameter . IsBufferAccessArray ( ) )
{
for ( FRDGBufferAccess BufferAccess : Parameter . GetAsBufferAccessArray ( ) )
{
BufferAccess - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
}
}
else if ( Parameter . IsTextureAccessArray ( ) )
{
for ( FRDGTextureAccess TextureAccess : Parameter . GetAsTextureAccessArray ( ) )
{
TextureAccess - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
}
}
2019-09-14 09:45:25 -04:00
else if ( Parameter . IsRenderTargetBindingSlots ( ) )
2019-07-16 13:08:56 -04:00
{
2020-07-06 18:58:26 -04:00
const FRenderTargetBindingSlots & RenderTargets = Parameter . GetAsRenderTargetBindingSlots ( ) ;
2019-07-16 13:08:56 -04:00
2020-07-06 18:58:26 -04:00
RenderTargets . Enumerate ( [ & ] ( FRenderTargetBinding RenderTarget )
2019-07-16 13:08:56 -04:00
{
2020-11-17 17:04:48 -04:00
RenderTarget . GetTexture ( ) - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
2020-09-24 00:43:27 -04:00
if ( FRDGTextureRef ResolveTexture = RenderTarget . GetResolveTexture ( ) )
{
2020-11-17 17:04:48 -04:00
ResolveTexture - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
2019-07-16 13:08:56 -04:00
2020-07-06 18:58:26 -04:00
if ( FRDGTextureRef Texture = RenderTargets . DepthStencil . GetTexture ( ) )
2019-07-16 13:08:56 -04:00
{
2020-11-17 17:04:48 -04:00
Texture - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
2019-07-16 13:08:56 -04:00
}
2021-03-05 16:16:14 -04:00
2021-03-05 18:33:15 -04:00
if ( FRDGTexture * Texture = RenderTargets . ShadingRateTexture )
2021-03-05 16:16:14 -04:00
{
Texture - > GetDebugData ( ) . bAllowRHIAccess = bAllowAccess ;
}
2019-07-16 13:08:56 -04:00
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-07-16 13:08:56 -04:00
}
2020-07-06 18:58:26 -04:00
FRDGBarrierValidation : : FRDGBarrierValidation ( const FRDGPassRegistry * InPasses , const FRDGEventName & InGraphName )
: Passes ( InPasses )
, GraphName ( InGraphName . GetTCHAR ( ) )
{
check ( Passes ) ;
}
2020-09-24 00:43:27 -04:00
void FRDGBarrierValidation : : ValidateBarrierBatchBegin ( const FRDGPass * Pass , const FRDGBarrierBatchBegin & Batch )
2020-07-06 18:58:26 -04:00
{
if ( ! GRDGTransitionLog )
{
return ;
}
2020-11-11 19:22:36 -04:00
FResourceMap * ResourceMap = BatchMap . Find ( & Batch ) ;
2020-07-06 18:58:26 -04:00
2020-11-11 19:22:36 -04:00
if ( ! ResourceMap )
2020-07-06 18:58:26 -04:00
{
2020-11-11 19:22:36 -04:00
ResourceMap = & BatchMap . Emplace ( & Batch ) ;
2020-07-06 18:58:26 -04:00
2020-11-11 19:22:36 -04:00
for ( int32 Index = 0 ; Index < Batch . Transitions . Num ( ) ; + + Index )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
FRDGParentResourceRef Resource = Batch . DebugTransitionResources [ Index ] ;
2020-11-11 19:22:36 -04:00
const FRHITransitionInfo & Transition = Batch . Transitions [ Index ] ;
if ( Resource - > Type = = ERDGParentResourceType : : Texture )
{
ResourceMap - > Textures . FindOrAdd ( static_cast < FRDGTextureRef > ( Resource ) ) . Add ( Transition ) ;
}
else
{
check ( Resource - > Type = = ERDGParentResourceType : : Buffer ) ;
ResourceMap - > Buffers . Emplace ( static_cast < FRDGBufferRef > ( Resource ) , Transition ) ;
}
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
for ( int32 Index = 0 ; Index < Batch . Aliases . Num ( ) ; + + Index )
{
ResourceMap - > Aliases . Emplace ( Batch . DebugAliasingResources [ Index ] , Batch . Aliases [ Index ] ) ;
}
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
if ( ! IsDebugAllowedForGraph ( GraphName ) | | ! IsDebugAllowedForPass ( Pass - > GetName ( ) ) )
2020-07-06 18:58:26 -04:00
{
return ;
}
bool bFoundFirst = false ;
const auto LogHeader = [ & ] ( )
{
if ( ! bFoundFirst )
{
bFoundFirst = true ;
2021-03-17 12:44:59 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " [%s(Index: %d, Pipeline: %s): %s] (Begin): " ) , Pass - > GetName ( ) , Pass - > GetHandle ( ) . GetIndex ( ) , * GetRHIPipelineName ( Pass - > GetPipeline ( ) ) , Batch . DebugName ) ;
2020-07-06 18:58:26 -04:00
}
} ;
2021-03-17 12:44:59 -04:00
for ( const auto & KeyValue : ResourceMap - > Aliases )
{
const FRHITransientAliasingInfo & Info = KeyValue . Value ;
if ( Info . IsAcquire ( ) )
{
FRDGParentResourceRef Resource = KeyValue . Key ;
if ( IsDebugAllowedForResource ( Resource - > Name ) )
{
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s - Acquire " ) , Resource , Resource - > GetRHIUnchecked ( ) , Resource - > Name ) ;
}
}
}
2020-11-11 19:22:36 -04:00
for ( const auto & Pair : ResourceMap - > Textures )
2020-07-06 18:58:26 -04:00
{
FRDGTextureRef Texture = Pair . Key ;
2021-03-17 12:44:59 -04:00
if ( ! IsDebugAllowedForResource ( Texture - > Name ) )
{
continue ;
}
2020-07-06 18:58:26 -04:00
const auto & Transitions = Pair . Value ;
2021-03-17 12:44:59 -04:00
if ( Transitions . Num ( ) )
2020-07-06 18:58:26 -04:00
{
LogHeader ( ) ;
2021-03-17 12:44:59 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s: " ) , Texture , Texture - > GetRHIUnchecked ( ) , Texture - > Name ) ;
2020-07-06 18:58:26 -04:00
}
const FRDGTextureSubresourceLayout SubresourceLayout = Texture - > GetSubresourceLayout ( ) ;
for ( const FRHITransitionInfo & Transition : Transitions )
{
check ( SubresourceLayout . GetSubresourceCount ( ) > 0 ) ;
EnumerateSubresources ( Transition , SubresourceLayout . NumMips , SubresourceLayout . NumArraySlices , SubresourceLayout . NumPlaneSlices ,
2020-09-24 00:43:27 -04:00
[ & ] ( FRDGTextureSubresource Subresource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
const int32 SubresourceIndex = SubresourceLayout . GetSubresourceIndex ( Subresource ) ;
2020-07-06 18:58:26 -04:00
2021-03-17 12:44:59 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " \t \t Mip(%d), Array(%d), Slice(%d): [%s, %s] -> [%s, %s] " ) ,
2020-09-24 00:43:27 -04:00
Subresource . MipIndex , Subresource . ArraySlice , Subresource . PlaneSlice ,
* GetRHIAccessName ( Transition . AccessBefore ) ,
2020-11-11 19:22:36 -04:00
* GetRHIPipelineName ( Batch . DebugPipelinesToBegin ) ,
* GetRHIAccessName ( Transition . AccessAfter ) ,
* GetRHIPipelineName ( Batch . DebugPipelinesToEnd ) ) ;
2020-07-06 18:58:26 -04:00
} ) ;
}
}
2021-03-17 12:44:59 -04:00
for ( const auto & Pair : ResourceMap - > Buffers )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
FRDGBufferRef Buffer = Pair . Key ;
const FRHITransitionInfo & Transition = Pair . Value ;
if ( ! IsDebugAllowedForResource ( Buffer - > Name ) )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
continue ;
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s: [%s, %s] -> [%s, %s] " ) ,
Buffer ,
Buffer - > GetRHIUnchecked ( ) ,
Buffer - > Name ,
* GetRHIAccessName ( Transition . AccessBefore ) ,
* GetRHIPipelineName ( Batch . DebugPipelinesToBegin ) ,
* GetRHIAccessName ( Transition . AccessAfter ) ,
* GetRHIPipelineName ( Batch . DebugPipelinesToEnd ) ) ;
2020-07-06 18:58:26 -04:00
}
}
2020-09-24 00:43:27 -04:00
void FRDGBarrierValidation : : ValidateBarrierBatchEnd ( const FRDGPass * Pass , const FRDGBarrierBatchEnd & Batch )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( ! GRDGTransitionLog | | ! IsDebugAllowedForGraph ( GraphName ) | | ! IsDebugAllowedForPass ( Pass - > GetName ( ) ) )
2020-07-06 18:58:26 -04:00
{
return ;
}
2021-03-17 12:44:59 -04:00
const bool bAllowedForPass = IsDebugAllowedForGraph ( GraphName ) & & IsDebugAllowedForPass ( Pass - > GetName ( ) ) ;
bool bFoundFirst = false ;
2020-07-06 18:58:26 -04:00
for ( const FRDGBarrierBatchBegin * Dependent : Batch . Dependencies )
{
2020-11-11 19:22:36 -04:00
if ( Dependent - > PipelinesToEnd = = ERHIPipeline : : None )
2020-07-06 18:58:26 -04:00
{
continue ;
}
const FResourceMap & ResourceMap = BatchMap . FindChecked ( Dependent ) ;
TArray < FRDGTextureRef > Textures ;
if ( ResourceMap . Textures . Num ( ) )
{
ResourceMap . Textures . GetKeys ( Textures ) ;
}
TArray < FRDGBufferRef > Buffers ;
if ( ResourceMap . Buffers . Num ( ) )
{
ResourceMap . Buffers . GetKeys ( Buffers ) ;
}
2021-03-17 12:44:59 -04:00
const auto LogHeader = [ & ] ( )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
if ( ! bFoundFirst )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
bFoundFirst = true ;
2020-11-11 19:22:36 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " [%s(Index: %d, Pipeline: %s) %s] (End): " ) , Pass - > GetName ( ) , Pass - > GetHandle ( ) . GetIndex ( ) , Dependent - > DebugName , * GetRHIPipelineName ( Pass - > GetPipeline ( ) ) ) ;
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
} ;
2020-07-06 18:58:26 -04:00
for ( FRDGTextureRef Texture : Textures )
{
2020-11-11 19:22:36 -04:00
if ( IsDebugAllowedForResource ( Texture - > Name ) )
{
2021-03-17 12:44:59 -04:00
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s - End: " ) , Texture , Texture - > GetRHIUnchecked ( ) , Texture - > Name ) ;
2020-11-11 19:22:36 -04:00
}
2020-07-06 18:58:26 -04:00
}
for ( FRDGBufferRef Buffer : Buffers )
{
2020-11-11 19:22:36 -04:00
if ( IsDebugAllowedForResource ( Buffer - > Name ) )
{
2021-03-17 12:44:59 -04:00
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s - End " ) , Buffer , Buffer - > GetRHIUnchecked ( ) , Buffer - > Name ) ;
}
}
for ( const auto & KeyValue : ResourceMap . Aliases )
{
const FRHITransientAliasingInfo & Info = KeyValue . Value ;
if ( Info . IsDiscard ( ) )
{
FRDGParentResourceRef Resource = KeyValue . Key ;
if ( IsDebugAllowedForResource ( Resource - > Name ) )
{
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t RDG(%p) RHI(%p) %s - Discard " ) , Resource , Resource - > GetRHIUnchecked ( ) , Resource - > Name ) ;
}
2020-11-11 19:22:36 -04:00
}
2020-07-06 18:58:26 -04:00
}
}
}
namespace
{
const TCHAR * RasterColorName = TEXT ( " #ff7070 " ) ;
const TCHAR * ComputeColorName = TEXT ( " #70b8ff " ) ;
const TCHAR * AsyncComputeColorName = TEXT ( " #70ff99 " ) ;
const TCHAR * CopyColorName = TEXT ( " #ffdb70 " ) ;
const TCHAR * TextureColorAttributes = TEXT ( " color= \" #5800a1 \" , fontcolor= \" #5800a1 \" " ) ;
const TCHAR * BufferColorAttributes = TEXT ( " color= \" #007309 \" , fontcolor= \" #007309 \" " ) ;
2020-09-24 00:43:27 -04:00
const TCHAR * AliasColorAttributes = TEXT ( " color= \" #00ff00 \" , fontcolor= \" #00ff00 \" " ) ;
2020-11-11 19:22:36 -04:00
const TCHAR * AllPipelinesColorName = TEXT ( " #f170ff " ) ;
2020-07-06 18:58:26 -04:00
const TCHAR * GetPassColorName ( ERDGPassFlags Flags )
{
if ( EnumHasAnyFlags ( Flags , ERDGPassFlags : : Raster ) )
{
return RasterColorName ;
}
if ( EnumHasAnyFlags ( Flags , ERDGPassFlags : : Compute ) )
{
return ComputeColorName ;
}
if ( EnumHasAnyFlags ( Flags , ERDGPassFlags : : AsyncCompute ) )
{
return AsyncComputeColorName ;
}
if ( EnumHasAnyFlags ( Flags , ERDGPassFlags : : Copy ) )
{
return CopyColorName ;
}
2020-09-24 00:43:27 -04:00
return TEXT ( " #ffffff " ) ;
2020-07-06 18:58:26 -04:00
}
FString GetSubresourceStateLabel ( FRDGSubresourceState State )
{
2020-11-11 19:22:36 -04:00
const ERHIPipeline Pipelines = State . GetPipelines ( ) ;
const TCHAR * FontColor = nullptr ;
switch ( Pipelines )
{
default :
checkNoEntry ( ) ;
case ERHIPipeline : : Graphics :
FontColor = RasterColorName ;
break ;
case ERHIPipeline : : AsyncCompute :
FontColor = AsyncComputeColorName ;
break ;
case ERHIPipeline : : All :
FontColor = AllPipelinesColorName ;
break ;
}
2020-09-24 00:43:27 -04:00
return FString : : Printf ( TEXT ( " <font color= \" %s \" >%s</font> " ) , FontColor , * GetRHIAccessName ( State . Access ) ) ;
2020-07-06 18:58:26 -04:00
}
}
FString FRDGLogFile : : GetProducerName ( FRDGPassHandle PassHandle )
{
2021-05-19 17:54:58 -04:00
check ( PassHandle . IsValid ( ) ) ;
return GetNodeName ( PassHandle ) ;
2020-07-06 18:58:26 -04:00
}
FString FRDGLogFile : : GetConsumerName ( FRDGPassHandle PassHandle )
{
2021-05-19 17:54:58 -04:00
check ( PassHandle . IsValid ( ) ) ;
return GetNodeName ( PassHandle ) ;
2020-07-06 18:58:26 -04:00
}
FString FRDGLogFile : : GetNodeName ( FRDGPassHandle PassHandle )
{
PassesReferenced . Add ( PassHandle ) ;
return FString : : Printf ( TEXT ( " P%d " ) , PassHandle . GetIndex ( ) ) ;
}
FString FRDGLogFile : : GetNodeName ( const FRDGTexture * Texture )
{
return FString : : Printf ( TEXT ( " T%d " ) , Textures . AddUnique ( Texture ) ) ;
}
FString FRDGLogFile : : GetNodeName ( const FRDGBuffer * Buffer )
{
return FString : : Printf ( TEXT ( " B%d " ) , Buffers . AddUnique ( Buffer ) ) ;
}
void FRDGLogFile : : AddLine ( const FString & Line )
{
File + = Indentation + Line + TEXT ( " \n " ) ;
}
void FRDGLogFile : : AddBraceBegin ( )
{
AddLine ( TEXT ( " { " ) ) ;
Indentation + = TEXT ( " \t " ) ;
}
void FRDGLogFile : : AddBraceEnd ( )
{
const bool bSuccess = Indentation . RemoveFromEnd ( TEXT ( " \t " ) ) ;
check ( bSuccess ) ;
AddLine ( TEXT ( " } " ) ) ;
}
2021-05-19 17:54:58 -04:00
void FRDGLogFile : : Begin ( const FRDGEventName & InGraphName )
2020-07-06 18:58:26 -04:00
{
if ( GRDGDumpGraph )
{
2021-03-17 12:44:59 -04:00
if ( IsImmediateMode ( ) )
2020-07-06 18:58:26 -04:00
{
UE_LOG ( LogRDG , Warning , TEXT ( " Dump graph (%d) requested, but immediate mode is enabled. Skipping. " ) , GRDGDumpGraph ) ;
return ;
}
check ( File . IsEmpty ( ) ) ;
GraphName = InGraphName . GetTCHAR ( ) ;
if ( GraphName . IsEmpty ( ) )
{
const int32 UnknownGraphIndex = GRDGDumpGraphUnknownCount + + ;
GraphName = FString : : Printf ( TEXT ( " Unknown%d " ) , UnknownGraphIndex ) ;
}
AddLine ( TEXT ( " digraph RDG " ) ) ;
AddBraceBegin ( ) ;
AddLine ( TEXT ( " rankdir=LR; labelloc= \" t \" " ) ) ;
bOpen = true ;
}
}
void FRDGLogFile : : End ( )
{
if ( ! GRDGDumpGraph | | ! bOpen )
{
return ;
}
TArray < FRDGPassHandle > PassesGraphics ;
TArray < FRDGPassHandle > PassesAsyncCompute ;
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = Passes . Begin ( ) ; PassHandle ! = Passes . End ( ) ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
const FRDGPass * Pass = Passes [ PassHandle ] ;
2020-09-24 00:43:27 -04:00
const ERHIPipeline Pipeline = Pass - > GetPipeline ( ) ;
2020-07-06 18:58:26 -04:00
switch ( Pipeline )
{
2020-09-24 00:43:27 -04:00
case ERHIPipeline : : Graphics :
2020-07-06 18:58:26 -04:00
PassesGraphics . Add ( PassHandle ) ;
break ;
2020-09-24 00:43:27 -04:00
case ERHIPipeline : : AsyncCompute :
2020-07-06 18:58:26 -04:00
PassesAsyncCompute . Add ( PassHandle ) ;
break ;
default :
checkNoEntry ( ) ;
}
}
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_TRACKS )
{
2020-09-24 00:43:27 -04:00
FRDGPassHandle PrevPassesByPipeline [ uint32 ( ERHIPipeline : : Num ) ] ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = Passes . Begin ( ) ; PassHandle ! = Passes . End ( ) ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
const FRDGPass * Pass = Passes [ PassHandle ] ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
if ( ! EnumHasAnyFlags ( Pass - > GetFlags ( ) , ERDGPassFlags : : Copy | ERDGPassFlags : : Raster | ERDGPassFlags : : Compute | ERDGPassFlags : : AsyncCompute ) )
{
continue ;
}
ERHIPipeline PassPipeline = Pass - > GetPipeline ( ) ;
checkf ( FMath : : IsPowerOfTwo ( uint32 ( PassPipeline ) ) , TEXT ( " This logic doesn't handle multi-pipe passes. " ) ) ;
uint32 PipeIndex = FMath : : FloorLog2 ( uint32 ( PassPipeline ) ) ;
FRDGPassHandle & PrevPassInPipelineHandle = PrevPassesByPipeline [ PipeIndex ] ;
2020-07-06 18:58:26 -04:00
if ( PrevPassInPipelineHandle . IsValid ( ) )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [style= \" filled \" , penwidth=2, color= \" %s \" ] " ) ,
* GetNodeName ( PrevPassInPipelineHandle ) , * GetNodeName ( PassHandle ) , GetPassColorName ( Pass - > GetFlags ( ) ) ) ) ;
}
2020-09-24 00:43:27 -04:00
if ( Pass - > GetPipeline ( ) = = ERHIPipeline : : AsyncCompute )
2020-07-06 18:58:26 -04:00
{
const auto AddCrossPipelineEdge = [ & ] ( FRDGPassHandle PassBefore , FRDGPassHandle PassAfter )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [penwidth=5, style= \" dashed \" color= \" #f003fc \" ] " ) ,
* GetNodeName ( PassBefore ) , * GetNodeName ( PassAfter ) ) ) ;
} ;
if ( Pass - > IsAsyncComputeBegin ( ) )
{
AddCrossPipelineEdge ( Pass - > GetGraphicsForkPass ( ) , PassHandle ) ;
}
if ( Pass - > IsAsyncComputeEnd ( ) )
{
AddCrossPipelineEdge ( PassHandle , Pass - > GetGraphicsJoinPass ( ) ) ;
}
}
PrevPassInPipelineHandle = PassHandle ;
}
}
2020-09-24 00:43:27 -04:00
else if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_PRODUCERS )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = Passes . Begin ( ) ; PassHandle < Passes . Last ( ) ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
const FRDGPass * Pass = Passes [ PassHandle ] ;
2020-07-06 18:58:26 -04:00
2020-11-11 19:22:36 -04:00
for ( const FRDGPassHandle ProducerHandle : Pass - > GetProducers ( ) )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
const FRDGPass * Producer = Passes [ ProducerHandle ] ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
File + = FString : : Printf ( TEXT ( " \t \" %s \" -> \" %s \" [penwidth=2, color= \" %s:%s \" ] \n " ) ,
* GetNodeName ( ProducerHandle ) , * GetNodeName ( PassHandle ) , GetPassColorName ( Pass - > GetFlags ( ) ) , GetPassColorName ( Producer - > GetFlags ( ) ) ) ;
2020-07-06 18:58:26 -04:00
}
}
}
AddLine ( TEXT ( " subgraph Passes " ) ) ;
AddBraceBegin ( ) ;
const auto AddPass = [ & ] ( FRDGPassHandle PassHandle )
{
if ( ! PassesReferenced . Contains ( PassHandle ) )
{
return ;
}
2021-05-19 17:54:58 -04:00
const FRDGPass * Pass = Passes [ PassHandle ] ;
const TCHAR * Style = Pass - > IsCulled ( ) ? TEXT ( " dashed " ) : TEXT ( " filled " ) ;
2020-07-06 18:58:26 -04:00
FString PassName = FString : : Printf ( TEXT ( " [%d]: %s " ) , PassHandle . GetIndex ( ) , Pass - > GetName ( ) ) ;
if ( Pass - > GetParameters ( ) . HasExternalOutputs ( ) )
{
PassName + = TEXT ( " \n (Has External UAVs) " ) ;
}
AddLine ( FString : : Printf ( TEXT ( " \" %s \" [shape=box, style=%s, label= \" %s \" , color= \" %s \" ] " ) , * GetNodeName ( PassHandle ) , Style , * PassName , GetPassColorName ( Pass - > GetFlags ( ) ) ) ) ;
} ;
{
uint32 RenderTargetClusterCount = 0 ;
for ( FRDGPassHandle PassHandle : PassesGraphics )
{
2021-05-19 17:54:58 -04:00
const FRDGPass * Pass = Passes [ PassHandle ] ;
2020-07-06 18:58:26 -04:00
if ( Pass - > IsMergedRenderPassBegin ( ) )
{
const uint32 RenderTargetClusterIndex = RenderTargetClusterCount + + ;
AddLine ( FString : : Printf ( TEXT ( " subgraph cluster_%d " ) , RenderTargetClusterIndex ) ) ;
AddBraceBegin ( ) ;
AddLine ( TEXT ( " style=filled;color= \" #ffe0e0 \" ;fontcolor= \" #aa0000 \" ;label= \" Render Pass Merge \" ;fontsize=10 " ) ) ;
}
AddPass ( PassHandle ) ;
if ( Pass - > IsMergedRenderPassEnd ( ) )
{
AddBraceEnd ( ) ;
}
}
}
for ( FRDGPassHandle PassHandle : PassesAsyncCompute )
{
AddPass ( PassHandle ) ;
}
AddBraceEnd ( ) ;
AddLine ( TEXT ( " subgraph Textures " ) ) ;
AddBraceBegin ( ) ;
for ( const FRDGTexture * Texture : Textures )
{
FString Line = FString : : Printf ( TEXT ( " \" %s \" [shape=oval, %s, label= \" %s " ) , * GetNodeName ( Texture ) , TextureColorAttributes , Texture - > Name ) ;
2020-09-24 00:43:27 -04:00
if ( Texture - > IsExternal ( ) )
2020-07-06 18:58:26 -04:00
{
Line + = TEXT ( " \n (External) " ) ;
}
Line + = TEXT ( " \" ] " ) ;
AddLine ( Line ) ;
}
AddBraceEnd ( ) ;
AddLine ( TEXT ( " subgraph Buffers " ) ) ;
AddBraceBegin ( ) ;
for ( const FRDGBuffer * Buffer : Buffers )
{
FString Line = FString : : Printf ( TEXT ( " \" %s \" [shape=oval, %s, label= \" %s " ) , * GetNodeName ( Buffer ) , BufferColorAttributes , Buffer - > Name ) ;
2020-09-24 00:43:27 -04:00
if ( Buffer - > IsExternal ( ) )
2020-07-06 18:58:26 -04:00
{
Line + = TEXT ( " \n (External) " ) ;
}
Line + = TEXT ( " \" ] " ) ;
AddLine ( Line ) ;
}
AddBraceEnd ( ) ;
2020-09-24 00:43:27 -04:00
uint32 NumPassesActive = 0 ;
uint32 NumPassesCulled = 0 ;
2021-05-19 17:54:58 -04:00
Passes . Enumerate ( [ & ] ( const FRDGPass * Pass )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
if ( Pass - > IsCulled ( ) )
2020-09-24 00:43:27 -04:00
{
NumPassesCulled + + ;
}
else
{
NumPassesActive + + ;
}
2021-05-19 17:54:58 -04:00
} ) ;
2020-09-24 00:43:27 -04:00
AddLine ( FString : : Printf ( TEXT ( " label= \" %s [Active Passes: %d, Culled Passes: %d, Textures: %d, Buffers: %d] \" " ) , * GraphName , NumPassesActive , NumPassesCulled , Textures . Num ( ) , Buffers . Num ( ) ) ) ;
2020-07-06 18:58:26 -04:00
AddBraceEnd ( ) ;
check ( Indentation . IsEmpty ( ) ) ;
const TCHAR * DumpType = TEXT ( " " ) ;
switch ( GRDGDumpGraph )
{
2020-09-24 00:43:27 -04:00
case RDG_DUMP_GRAPH_RESOURCES :
DumpType = TEXT ( " _resources " ) ;
2020-07-06 18:58:26 -04:00
break ;
2020-09-24 00:43:27 -04:00
case RDG_DUMP_GRAPH_PRODUCERS :
DumpType = TEXT ( " _producers " ) ;
2020-07-06 18:58:26 -04:00
break ;
case RDG_DUMP_GRAPH_TRACKS :
DumpType = TEXT ( " _tracks " ) ;
break ;
}
FFileHelper : : SaveStringToFile ( File , * ( FPaths : : ProjectLogDir ( ) / FString : : Printf ( TEXT ( " RDG_%s%s.gv " ) , * GraphName , DumpType ) ) ) ;
bOpen = false ;
}
2020-09-24 00:43:27 -04:00
bool FRDGLogFile : : IncludeTransitionEdgeInGraph ( FRDGPassHandle Pass ) const
{
2021-05-19 17:54:58 -04:00
return Pass . IsValid ( ) & & ! Passes [ Pass ] - > IsSentinel ( ) ;
2020-09-24 00:43:27 -04:00
}
bool FRDGLogFile : : IncludeTransitionEdgeInGraph ( FRDGPassHandle PassBefore , FRDGPassHandle PassAfter ) const
{
return IncludeTransitionEdgeInGraph ( PassBefore ) & & IncludeTransitionEdgeInGraph ( PassAfter ) & & PassBefore < PassAfter ;
}
2020-07-06 18:58:26 -04:00
void FRDGLogFile : : AddFirstEdge ( const FRDGTextureRef Texture , FRDGPassHandle FirstPass )
{
2021-03-17 12:44:59 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( FirstPass ) & & IsDebugAllowedForResource ( Texture - > Name ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s] " ) ,
* GetNodeName ( Texture ) ,
* GetNodeName ( FirstPass ) ,
TextureColorAttributes ) ) ;
}
}
void FRDGLogFile : : AddFirstEdge ( const FRDGBufferRef Buffer , FRDGPassHandle FirstPass )
{
2021-03-17 12:44:59 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( FirstPass ) & & IsDebugAllowedForResource ( Buffer - > Name ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s] " ) ,
* GetNodeName ( Buffer ) ,
* GetNodeName ( FirstPass ) ,
BufferColorAttributes ) ) ;
}
}
2020-09-24 00:43:27 -04:00
void FRDGLogFile : : AddAliasEdge ( const FRDGTextureRef TextureBefore , FRDGPassHandle BeforePass , const FRDGTextureRef TextureAfter , FRDGPassHandle AfterPass )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( BeforePass , AfterPass ) & & IsDebugAllowedForResource ( TextureBefore - > Name ) & & IsDebugAllowedForResource ( TextureAfter - > Name ) )
2020-09-24 00:43:27 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<Alias: <b>%s -> %s</b>>] " ) ,
* GetProducerName ( BeforePass ) ,
* GetConsumerName ( AfterPass ) ,
AliasColorAttributes ,
TextureBefore - > Name ,
TextureAfter - > Name ) ) ;
}
}
void FRDGLogFile : : AddAliasEdge ( const FRDGBufferRef BufferBefore , FRDGPassHandle BeforePass , const FRDGBufferRef BufferAfter , FRDGPassHandle AfterPass )
{
2021-03-17 12:44:59 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( BeforePass , AfterPass ) & & IsDebugAllowedForResource ( BufferBefore - > Name ) & & IsDebugAllowedForResource ( BufferAfter - > Name ) )
2020-09-24 00:43:27 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<Alias: <b>%s -> %s</b>>] " ) ,
* GetProducerName ( BeforePass ) ,
* GetConsumerName ( AfterPass ) ,
AliasColorAttributes ,
BufferBefore - > Name ,
BufferAfter - > Name ) ) ;
}
}
2021-05-25 17:11:34 -04:00
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , const FRDGSubresourceState & StateBefore , const FRDGSubresourceState & StateAfter , const FRDGTextureRef Texture )
2020-09-24 00:43:27 -04:00
{
2021-05-25 17:11:34 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IsDebugAllowedForResource ( Texture - > Name ) )
2020-07-06 18:58:26 -04:00
{
2021-05-25 17:11:34 -04:00
if ( IncludeTransitionEdgeInGraph ( StateBefore . GetLastPass ( ) , StateAfter . GetFirstPass ( ) ) & & FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s -> %s</b>>] " ) ,
2020-11-11 19:22:36 -04:00
* GetProducerName ( StateBefore . GetLastPass ( ) ) ,
* GetConsumerName ( StateAfter . GetFirstPass ( ) ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ,
* GetSubresourceStateLabel ( StateAfter ) ) ) ;
}
2021-05-25 17:11:34 -04:00
else if ( IncludeTransitionEdgeInGraph ( StateBefore . LogFilePass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s</b>>] " ) ,
2021-05-25 17:11:34 -04:00
* GetProducerName ( StateBefore . LogFilePass ) ,
2020-09-24 00:43:27 -04:00
* GetConsumerName ( PassHandle ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ) ) ;
}
2021-05-25 17:11:34 -04:00
StateAfter . LogFilePass = PassHandle ;
2020-07-06 18:58:26 -04:00
}
}
2021-05-25 17:11:34 -04:00
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , const FRDGSubresourceState & StateBefore , const FRDGSubresourceState & StateAfter , const FRDGTextureRef Texture , FRDGTextureSubresource Subresource )
2020-07-06 18:58:26 -04:00
{
2021-05-25 17:11:34 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IsDebugAllowedForResource ( Texture - > Name ) )
2020-07-06 18:58:26 -04:00
{
2021-05-25 17:11:34 -04:00
if ( IncludeTransitionEdgeInGraph ( StateBefore . GetLastPass ( ) , StateAfter . GetFirstPass ( ) ) & & FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s[%d][%d][%d]: <b>%s -> %s</b>>] " ) ,
2020-11-11 19:22:36 -04:00
* GetProducerName ( StateBefore . GetLastPass ( ) ) ,
* GetConsumerName ( StateAfter . GetFirstPass ( ) ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
2020-09-24 00:43:27 -04:00
Subresource . MipIndex , Subresource . ArraySlice , Subresource . PlaneSlice ,
2020-07-06 18:58:26 -04:00
* GetSubresourceStateLabel ( StateBefore ) ,
* GetSubresourceStateLabel ( StateAfter ) ) ) ;
}
2021-05-25 17:11:34 -04:00
else if ( IncludeTransitionEdgeInGraph ( StateBefore . LogFilePass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s[%d][%d][%d]: <b>%s</b>>] " ) ,
2021-05-25 17:11:34 -04:00
* GetProducerName ( StateBefore . LogFilePass ) ,
2020-09-24 00:43:27 -04:00
* GetConsumerName ( PassHandle ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
2020-09-24 00:43:27 -04:00
Subresource . MipIndex , Subresource . ArraySlice , Subresource . PlaneSlice ,
2020-07-06 18:58:26 -04:00
* GetSubresourceStateLabel ( StateBefore ) ) ) ;
}
2021-05-25 17:11:34 -04:00
StateAfter . LogFilePass = PassHandle ;
2020-07-06 18:58:26 -04:00
}
}
2021-05-25 17:11:34 -04:00
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , const FRDGSubresourceState & StateBefore , const FRDGSubresourceState & StateAfter , const FRDGBufferRef Buffer )
2020-07-06 18:58:26 -04:00
{
2021-05-25 17:11:34 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IsDebugAllowedForResource ( Buffer - > Name ) )
2020-07-06 18:58:26 -04:00
{
2021-05-25 17:11:34 -04:00
if ( IncludeTransitionEdgeInGraph ( StateBefore . GetLastPass ( ) , StateAfter . GetFirstPass ( ) ) & & FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s -> %s</b>>] " ) ,
2020-11-11 19:22:36 -04:00
* GetProducerName ( StateBefore . GetLastPass ( ) ) ,
* GetConsumerName ( StateAfter . GetFirstPass ( ) ) ,
2020-07-06 18:58:26 -04:00
BufferColorAttributes ,
Buffer - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ,
* GetSubresourceStateLabel ( StateAfter ) ) ) ;
}
2021-05-25 17:11:34 -04:00
else if ( IncludeTransitionEdgeInGraph ( StateBefore . LogFilePass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s</b>>] " ) ,
2021-05-25 17:11:34 -04:00
* GetProducerName ( StateBefore . LogFilePass ) ,
2020-09-24 00:43:27 -04:00
* GetConsumerName ( PassHandle ) ,
2020-07-06 18:58:26 -04:00
BufferColorAttributes ,
Buffer - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ) ) ;
}
2021-05-25 17:11:34 -04:00
StateAfter . LogFilePass = PassHandle ;
2020-07-06 18:58:26 -04:00
}
}
2020-11-11 19:22:36 -04:00
# endif