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
2019-09-14 09:45:25 -04:00
/** Validates that we are only executing a single render graph instance in the callstack. Used to catch if a
* user creates a second FRDGBuilder instance inside of a pass that is executing .
*/
2020-07-06 18:58:26 -04:00
bool GRDGInExecutePassScope = false ;
} //! namespace
2019-07-16 13:08:56 -04:00
2020-10-23 16:26:52 -04:00
FRDGUserValidation : : FRDGUserValidation ( )
: ExpectedNumMarks ( FMemStack : : Get ( ) . GetNumMarks ( ) )
{ }
2019-07-16 13:08:56 -04:00
FRDGUserValidation : : ~ FRDGUserValidation ( )
{
checkf ( bHasExecuted , TEXT ( " Render graph execution is required to ensure consistency with immediate mode. " ) ) ;
}
2020-10-23 16:26:52 -04:00
void FRDGUserValidation : : MemStackGuard ( )
{
checkf ( ExpectedNumMarks = = FMemStack : : Get ( ) . GetNumMarks ( ) , TEXT ( " A MemStack mark was added during the FRDGBuilder lifetime. This is not allowed as it will free memory still used by the builder. " ) ) ;
}
2019-07-16 13:08:56 -04:00
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-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-07-16 13:08:56 -04:00
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : ValidateCreateTexture ( FRDGTextureRef Texture )
2019-07-16 13:08:56 -04:00
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-09-14 09:45:25 -04:00
check ( Texture ) ;
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-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-09-14 09:45:25 -04:00
check ( Buffer ) ;
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
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : ValidateCreateExternalTexture ( FRDGTextureRef Texture )
{
ValidateCreateTexture ( Texture ) ;
2020-07-06 18:58:26 -04:00
Texture - > ParentDebugData . bHasBeenProduced = true ;
2019-09-14 09:45:25 -04:00
}
void FRDGUserValidation : : ValidateCreateExternalBuffer ( FRDGBufferRef Buffer )
{
ValidateCreateBuffer ( Buffer ) ;
2020-07-06 18:58:26 -04:00
Buffer - > ParentDebugData . bHasBeenProduced = true ;
2019-09-14 09:45:25 -04:00
}
void FRDGUserValidation : : ValidateExtractResource ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-07-16 13:08:56 -04:00
check ( Resource ) ;
2020-07-06 18:58:26 -04:00
checkf ( Resource - > ParentDebugData . bHasBeenProduced ,
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-07-06 18:58:26 -04:00
Resource - > ParentDebugData . PassAccessCount + + ;
2019-07-16 13:08:56 -04:00
}
2019-09-14 09:45:25 -04:00
void FRDGUserValidation : : RemoveUnusedWarning ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-07-16 13:08:56 -04:00
check ( Resource ) ;
2019-09-14 09:45:25 -04:00
// Removes 'produced but not used' warning.
2020-07-06 18:58:26 -04:00
Resource - > ParentDebugData . PassAccessCount + + ;
2019-09-14 09:45:25 -04:00
// Removes 'not used' warning.
2020-07-06 18:58:26 -04:00
Resource - > DebugData . bIsActuallyUsedByPass = true ;
}
bool FRDGUserValidation : : TryMarkForClobber ( FRDGParentResourceRef Resource ) const
{
2020-09-24 00:43:27 -04:00
const bool bClobber = ! Resource - > ParentDebugData . bHasBeenClobbered & & ! Resource - > bExternal & & IsDebugAllowedForResource ( Resource - > Name ) ;
2020-07-06 18:58:26 -04:00
if ( bClobber )
{
Resource - > ParentDebugData . bHasBeenClobbered = true ;
}
return bClobber ;
2019-07-16 13:08:56 -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
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
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 ( ) ;
2020-07-06 18:58:26 -04:00
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-07-06 18:58:26 -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-07-06 18:58:26 -04:00
auto & Debug = Resource - > ParentDebugData ;
if ( ! Debug . bHasBeenProduced )
{
Debug . bHasBeenProduced = true ;
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-07-06 18:58:26 -04:00
const auto MarkAsConsumed = [ & ] ( FRDGParentResourceRef Resource )
2019-07-16 13:08:56 -04:00
{
2020-07-06 18:58:26 -04:00
auto & Debug = Resource - > ParentDebugData ;
ensureMsgf ( Debug . bHasBeenProduced ,
TEXT ( " Pass %s has a read dependency on %s, but it was never written to. " ) ,
PassName , Resource - > Name ) ;
if ( ! bSkipPassAccessMarking )
{
Debug . PassAccessCount + + ;
}
} ;
2020-09-24 00:43:27 -04:00
const auto CheckNotPassthrough = [ & ] ( FRDGResourceRef Resource )
{
checkf ( ! Resource - > IsPassthrough ( ) , TEXT ( " Resource '%s' was created as a passthrough resource but is attached to pass '%s'. " ) , Resource - > Name , Pass - > GetName ( ) ) ;
} ;
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
2020-09-24 00:43:27 -04:00
PassParameters . Enumerate ( [ & ] ( FRDGParameter Parameter )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( Parameter . IsParentResource ( ) )
{
if ( FRDGParentResourceRef Resource = Parameter . GetAsParentResource ( ) )
{
CheckNotPassthrough ( Resource ) ;
}
}
else if ( Parameter . IsView ( ) )
{
if ( FRDGViewRef View = Parameter . GetAsView ( ) )
{
CheckNotPassthrough ( View ) ;
CheckNotPassthrough ( View - > GetParent ( ) ) ;
}
}
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 ) ;
2019-09-14 09:45:25 -04:00
MarkAsProduced ( Texture ) ;
2019-07-16 13:08:56 -04:00
}
}
break ;
case UBMT_RDG_BUFFER :
{
if ( FRDGBufferRef Buffer = Parameter . GetAsBuffer ( ) )
{
2019-09-14 09:45:25 -04:00
MarkAsConsumed ( Buffer ) ;
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 ) ;
2019-09-14 09:45:25 -04:00
MarkAsProduced ( Buffer ) ;
}
}
break ;
2020-09-24 00:43:27 -04:00
case UBMT_RDG_TEXTURE_ACCESS :
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
const FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) ;
const ERHIAccess Access = TextureAccess . GetAccess ( ) ;
const bool bIsWriteAccess = IsWritableAccess ( Access ) ;
bCanProduce | = bIsWriteAccess ;
if ( FRDGTextureRef Texture = TextureAccess . GetTexture ( ) )
2019-09-14 09:45:25 -04:00
{
2020-10-14 14:20:26 -04:00
checkf ( bIsCopy | | ! EnumHasAnyFlags ( Access , AccessMaskCopy ) , TEXT ( " Pass '%s' uses texture '%s' with access '%s' containing states which require the 'ERDGPass::Copy' flag. " ) , Pass - > GetName ( ) , Texture - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsAnyCompute | | ! EnumHasAnyFlags ( Access , AccessMaskCompute ) , TEXT ( " Pass '%s' uses texture '%s' with access '%s' containing states which require the 'ERDGPass::Compute' or 'ERDGPassFlags::AsyncCompute' flag. " ) , Pass - > GetName ( ) , Texture - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskRaster ) , TEXT ( " Pass '%s' uses texture '%s' with access '%s' containing states which require the 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Texture - > Name , * GetRHIAccessName ( Access ) ) ;
2020-11-05 11:20:37 -04:00
checkf ( bIsAnyCompute | | bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskComputeOrRaster ) , TEXT ( " Pass '%s' uses texture '%s' with access '%s' containing states which require the 'ERDGPassFlags::Compute' or 'ERDGPassFlags::AsyncCompute' or 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Texture - > Name , * GetRHIAccessName ( Access ) ) ;
2020-09-24 00:43:27 -04:00
if ( bIsWriteAccess )
{
MarkAsProduced ( Texture ) ;
}
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
{
2020-09-24 00:43:27 -04:00
const FRDGBufferAccess BufferAccess = Parameter . GetAsBufferAccess ( ) ;
const ERHIAccess Access = BufferAccess . GetAccess ( ) ;
const bool bIsWriteAccess = IsWritableAccess ( Access ) ;
bCanProduce | = bIsWriteAccess ;
if ( FRDGBufferRef Buffer = BufferAccess . GetBuffer ( ) )
2019-09-14 09:45:25 -04:00
{
2020-10-14 14:20:26 -04:00
checkf ( bIsCopy | | ! EnumHasAnyFlags ( Access , AccessMaskCopy ) , TEXT ( " Pass '%s' uses buffer '%s' with access '%s' containing states which require the 'ERDGPass::Copy' flag. " ) , Pass - > GetName ( ) , Buffer - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsAnyCompute | | ! EnumHasAnyFlags ( Access , AccessMaskCompute ) , TEXT ( " Pass '%s' uses buffer '%s' with access '%s' containing states which require the 'ERDGPass::Compute' or 'ERDGPassFlags::AsyncCompute' flag. " ) , Pass - > GetName ( ) , Buffer - > Name , * GetRHIAccessName ( Access ) ) ;
checkf ( bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskRaster ) , TEXT ( " Pass '%s' uses buffer '%s' with access '%s' containing states which require the 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Buffer - > Name , * GetRHIAccessName ( Access ) ) ;
2020-11-05 11:20:37 -04:00
checkf ( bIsAnyCompute | | bIsRaster | | ! EnumHasAnyFlags ( Access , AccessMaskComputeOrRaster ) , TEXT ( " Pass '%s' uses buffer '%s' with access '%s' containing states which require the 'ERDGPassFlags::Compute' or 'ERDGPassFlags::AsyncCompute' or 'ERDGPass::Raster' flag. " ) , Pass - > GetName ( ) , Buffer - > Name , * GetRHIAccessName ( Access ) ) ;
2020-09-24 00:43:27 -04:00
if ( IsWritableAccess ( BufferAccess . GetAccess ( ) ) )
{
MarkAsProduced ( Buffer ) ;
}
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 ;
{
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 ) ;
2020-09-24 00:43:27 -04:00
CheckNotPassthrough ( Texture ) ;
2019-07-16 13:08:56 -04:00
if ( DepthStencil . GetDepthStencilAccess ( ) . IsAnyWrite ( ) )
{
2019-09-14 09:45:25 -04:00
MarkAsProduced ( 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. */
uint32 ValidRenderTargetCount = 0 ;
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 ) ;
CheckNotPassthrough ( ResolveTexture ) ;
MarkAsProduced ( ResolveTexture ) ;
}
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 ) ;
2020-09-24 00:43:27 -04:00
CheckNotPassthrough ( Texture ) ;
const bool bIsLoadAction = RenderTarget . GetLoadAction ( ) = = ERenderTargetLoadAction : : ELoad ;
2019-07-23 17:49:47 -04:00
/** Validate that load action is correct. We can only load contents if a pass previously produced something. */
{
2020-07-06 18:58:26 -04:00
const bool bIsLoadActionInvalid = bIsLoadAction & & ! Texture - > ParentDebugData . bHasBeenProduced ;
2019-07-23 17:49:47 -04:00
checkf (
! bIsLoadActionInvalid ,
TEXT ( " Pass '%s' attempted to bind texture '%s' as a render target with the 'Load' action specified, but the texture has not been produced yet. The render target must use either 'Clear' or 'NoAction' action instead. " ) ,
PassName ,
Texture - > Name ) ;
}
/** Validate that any previously produced texture contents are loaded. This occurs if the user failed to specify a load action
* on a texture that was produced by a previous pass , effectively losing that data . This can also happen if the user ' re - uses '
* a texture for some other purpose . The latter is considered bad practice , since it increases memory pressure on the render
* target pool . Instead , the user should create a new texture instance . An exception to this rule are untracked render targets ,
* which are not actually managed by the render target pool and likely represent the frame buffer .
*/
{
2019-09-14 09:45:25 -04:00
// Ignore external textures which are always marked as produced. We don't need to enforce this warning on them.
2020-09-24 00:43:27 -04:00
const bool bHasBeenProduced = Texture - > ParentDebugData . bHasBeenProduced & & ! Texture - > bExternal ;
2019-09-14 09:45:25 -04:00
2019-07-23 17:49:47 -04:00
// We only validate single-mip textures since we don't track production at the subresource level.
2019-09-14 09:45:25 -04:00
const bool bFailedToLoadProducedContent = ! bIsLoadAction & & bHasBeenProduced & & Texture - > Desc . NumMips = = 1 ;
2019-07-23 17:49:47 -04:00
// Untracked render targets aren't actually managed by the render target pool.
2020-09-24 00:43:27 -04:00
const bool bIsUntrackedRenderTarget = Texture - > PooledRenderTarget & & ! Texture - > PooledRenderTarget - > IsTracked ( ) ;
2019-07-23 17:49:47 -04:00
2020-09-24 00:43:27 -04:00
// In multi-gpu, when running with "r.EnableMultiGPUForkAndJoin", it's possible for each GPU to clear the same RT in turn.
// When this happens, they are not actually working on the same resource, see for example the implementation of FD3D12MultiNodeGPUObject.
ensureMsgf ( ( ! bFailedToLoadProducedContent | | bIsUntrackedRenderTarget ) | | ( GNumExplicitGPUsForRendering > 1 & & RenderTarget . GetLoadAction ( ) = = ERenderTargetLoadAction : : EClear ) ,
2019-07-23 17:49:47 -04:00
TEXT ( " Pass '%s' attempted to bind texture '%s' as a render target without the 'Load' action specified, despite a prior pass having produced it. It's invalid to completely clobber the contents of a resource. Create a new texture instance instead. " ) ,
PassName ,
Texture - > Name ) ;
}
2019-07-16 13:08:56 -04:00
/** Mark the pass as a producer for render targets with a store action. */
2019-09-14 09:45:25 -04:00
MarkAsProduced ( 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 ( )
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-07-16 13:08:56 -04:00
checkf ( ! bHasExecuted , TEXT ( " Render graph execution should only happen once to ensure consistency with immediate mode. " ) ) ;
}
void FRDGUserValidation : : ValidateExecuteEnd ( )
{
2020-10-23 16:26:52 -04:00
MemStackGuard ( ) ;
2019-07-16 13:08:56 -04:00
bHasExecuted = true ;
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
{
2019-09-14 09:45:25 -04:00
check ( Resource - > ReferenceCount = = 0 ) ;
2019-07-16 13:08:56 -04:00
2020-07-06 18:58:26 -04:00
const auto & ParentDebugData = Resource - > ParentDebugData ;
const bool bProducedButNeverUsed = ParentDebugData . PassAccessCount = = 1 & & ParentDebugData . FirstProducer ;
2019-09-14 09:45:25 -04:00
if ( bProducedButNeverUsed )
{
2020-07-06 18:58:26 -04:00
check ( ParentDebugData . bHasBeenProduced ) ;
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-09-24 00:43:27 -04:00
const bool bHasBeenProducedByGraph = ! Texture - > bExternal & & Texture - > ParentDebugData . PassAccessCount > 0 ;
2019-09-14 09:45:25 -04:00
2020-09-24 00:43:27 -04:00
if ( bHasBeenProducedByGraph & & ! Texture - > 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-07-06 18:58:26 -04:00
Texture - > Name , Texture - > ParentDebugData . FirstProducer - > GetName ( ) ) ;
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
if ( bHasBeenProducedByGraph & & ! Texture - > 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-07-06 18:58:26 -04:00
Texture - > Name , Texture - > 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 )
{
2020-07-06 18:58:26 -04:00
check ( Pass ) ;
2019-09-14 09:45:25 -04:00
checkf ( ! GRDGInExecutePassScope , TEXT ( " Render graph is being executed recursively. This usually means a separate FRDGBuilder instance was created inside of an executing pass. " ) ) ;
GRDGInExecutePassScope = true ;
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-09-24 00:43:27 -04:00
Pass - > GetParameters ( ) . EnumerateUniformBuffers ( [ & ] ( FRDGUniformBufferRef 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.
if ( UniformBuffer - > IsGlobal ( ) )
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
UniformBuffer - > MarkResourceAsUsed ( ) ;
}
} ) ;
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-07-06 18:58:26 -04:00
Texture - > TextureDebugData . bHasNeededUAV = true ;
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
break ;
case UBMT_RDG_TEXTURE_ACCESS :
2020-10-26 12:05:19 -04:00
{
const FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) ;
if ( FRDGTextureRef Texture = TextureAccess . GetTexture ( ) )
2020-09-24 00:43:27 -04:00
{
2020-10-26 12:05:19 -04:00
const ERHIAccess Access = TextureAccess . GetAccess ( ) ;
if ( EnumHasAnyFlags ( Access , ERHIAccess : : UAVMask ) )
{
Texture - > TextureDebugData . bHasNeededUAV = true ;
}
if ( EnumHasAnyFlags ( Access , ERHIAccess : : RTV | ERHIAccess : : DSVRead | ERHIAccess : : DSVWrite ) )
{
Texture - > TextureDebugData . bHasBeenBoundAsRenderTarget = true ;
}
Texture - > MarkResourceAsUsed ( ) ;
}
}
break ;
case UBMT_RDG_BUFFER_ACCESS :
if ( FRDGBufferRef Buffer = Parameter . GetAsBuffer ( ) )
{
Buffer - > MarkResourceAsUsed ( ) ;
2020-09-24 00:43:27 -04:00
}
break ;
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 ( ) ;
Texture - > TextureDebugData . bHasBeenBoundAsRenderTarget = true ;
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-07-06 18:58:26 -04:00
Texture - > TextureDebugData . bHasBeenBoundAsRenderTarget = true ;
2020-09-24 00:43:27 -04:00
Texture - > MarkResourceAsUsed ( ) ;
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 )
{
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-07-06 18:58:26 -04:00
UsedResourceCount + = Resource - > DebugData . 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-07-06 18:58:26 -04:00
if ( ! Resource - > DebugData . 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-07-06 18:58:26 -04:00
Resource - > DebugData . bIsActuallyUsedByPass = false ;
2019-07-16 13:08:56 -04:00
}
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-09-14 09:45:25 -04:00
GRDGInExecutePassScope = false ;
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-07-06 18:58:26 -04:00
Resource - > DebugData . bAllowRHIAccess = bAllowAccess ;
2019-07-16 13:08:56 -04:00
}
}
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-07-06 18:58:26 -04:00
RenderTarget . GetTexture ( ) - > DebugData . bAllowRHIAccess = bAllowAccess ;
2020-09-24 00:43:27 -04:00
if ( FRDGTextureRef ResolveTexture = RenderTarget . GetResolveTexture ( ) )
{
ResolveTexture - > DebugData . bAllowRHIAccess = bAllowAccess ;
}
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-07-06 18:58:26 -04:00
Texture - > DebugData . 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
{
checkf ( ! Batch . IsTransitionValid ( ) & & ! BatchMap . Contains ( & Batch ) , TEXT ( " Begin barrier batch '%s' has already been submitted. " ) , * Batch . GetName ( ) ) ;
if ( ! GRDGTransitionLog )
{
return ;
}
FResourceMap & ResourceMap = BatchMap . Emplace ( & Batch ) ;
for ( int32 Index = 0 ; Index < Batch . Transitions . Num ( ) ; + + Index )
{
FRDGParentResourceRef Resource = Batch . Resources [ Index ] ;
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 ) ;
FRDGBufferRef Buffer = static_cast < FRDGBufferRef > ( Resource ) ;
checkf ( ! ResourceMap . Buffers . Contains ( Buffer ) , TEXT ( " Buffer %s was added multiple times to batch %s. " ) , Buffer - > Name , * Batch . GetName ( ) ) ;
ResourceMap . Buffers . Emplace ( Buffer , Transition ) ;
}
}
2020-09-24 00:43:27 -04:00
const bool bAllowedForPass = IsDebugAllowedForGraph ( GraphName ) & & IsDebugAllowedForPass ( Pass - > GetName ( ) ) ;
// Debug mode will report errors regardless of logging filter.
if ( ! bAllowedForPass & & ! GRDGDebug )
2020-07-06 18:58:26 -04:00
{
return ;
}
bool bFoundFirst = false ;
const auto LogHeader = [ & ] ( )
{
if ( ! bFoundFirst )
{
bFoundFirst = true ;
2020-09-24 00:43:27 -04:00
UE_CLOG ( bAllowedForPass , LogRDG , Display , TEXT ( " %s (Begin): " ) , * Batch . GetName ( ) ) ;
2020-07-06 18:58:26 -04:00
}
} ;
2020-09-21 16:17:38 -04:00
for ( const auto & Pair : ResourceMap . Textures )
2020-07-06 18:58:26 -04:00
{
FRDGTextureRef Texture = Pair . Key ;
2020-09-24 00:43:27 -04:00
const bool bAllowedForResource = bAllowedForPass & & IsDebugAllowedForResource ( Texture - > Name ) ;
2020-07-06 18:58:26 -04:00
const auto & Transitions = Pair . Value ;
2020-09-24 00:43:27 -04:00
if ( bAllowedForResource & & Transitions . Num ( ) )
2020-07-06 18:58:26 -04:00
{
LogHeader ( ) ;
2020-09-24 00:43:27 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " \t (%p) %s: " ) , Texture , 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
2020-09-24 00:43:27 -04:00
UE_CLOG ( bAllowedForResource , LogRDG , Display , TEXT ( " \t \t Mip(%d), Array(%d), Slice(%d): %s -> %s " ) ,
Subresource . MipIndex , Subresource . ArraySlice , Subresource . PlaneSlice ,
* GetRHIAccessName ( Transition . AccessBefore ) ,
* GetRHIAccessName ( Transition . AccessAfter ) ) ;
2020-07-06 18:58:26 -04:00
} ) ;
}
}
2020-09-24 00:43:27 -04:00
if ( bAllowedForPass )
2020-07-06 18:58:26 -04:00
{
2020-10-29 13:38:15 -04:00
for ( auto Pair : ResourceMap . Buffers )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGBufferRef Buffer = Pair . Key ;
const FRHITransitionInfo & Transition = Pair . Value ;
if ( ! IsDebugAllowedForResource ( Buffer - > Name ) )
{
continue ;
}
LogHeader ( ) ;
UE_LOG ( LogRDG , Display , TEXT ( " \t (%p) %s: %s -> %s " ) ,
Buffer ,
Buffer - > Name ,
* GetRHIAccessName ( Transition . AccessBefore ) ,
* GetRHIAccessName ( Transition . AccessAfter ) ) ;
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 ;
}
bool bFoundFirstBatch = false ;
for ( const FRDGBarrierBatchBegin * Dependent : Batch . Dependencies )
{
// Transitions can be queued into multiple end batches. The first to get flushed nulls out the transition.
if ( ! Dependent - > IsTransitionValid ( ) )
{
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 ) ;
}
if ( Textures . Num ( ) | | Buffers . Num ( ) )
{
if ( ! bFoundFirstBatch )
{
UE_LOG ( LogRDG , Display , TEXT ( " %s (End): " ) , * Batch . GetName ( ) ) ;
bFoundFirstBatch = true ;
}
}
for ( FRDGTextureRef Texture : Textures )
{
2020-09-24 00:43:27 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " \t (%p) %s " ) , Texture , Texture - > Name ) ;
2020-07-06 18:58:26 -04:00
}
for ( FRDGBufferRef Buffer : Buffers )
{
2020-09-24 00:43:27 -04:00
UE_LOG ( LogRDG , Display , TEXT ( " \t (%p) %s " ) , Buffer , Buffer - > Name ) ;
2020-07-06 18:58:26 -04:00
}
}
}
void FRDGBarrierValidation : : ValidateExecuteEnd ( )
{
for ( auto Pair : BatchMap )
{
checkf ( ! Pair . Key - > IsTransitionValid ( ) , TEXT ( " A batch was begun but never ended. " ) ) ;
}
BatchMap . Empty ( ) ;
}
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-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-09-24 00:43:27 -04:00
check ( State . Pipeline = = ERHIPipeline : : Graphics | | State . Pipeline = = ERHIPipeline : : AsyncCompute ) ;
const TCHAR * FontColor = State . Pipeline = = ERHIPipeline : : AsyncCompute ? AsyncComputeColorName : RasterColorName ;
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 )
{
if ( PassHandle . IsValid ( ) )
{
return GetNodeName ( PassHandle ) ;
}
else
{
return GetNodeName ( ProloguePassHandle ) ;
}
}
FString FRDGLogFile : : GetConsumerName ( FRDGPassHandle PassHandle )
{
if ( PassHandle . IsValid ( ) )
{
return GetNodeName ( PassHandle ) ;
}
else
{
return GetNodeName ( EpiloguePassHandle ) ;
}
}
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 ( " } " ) ) ;
}
void FRDGLogFile : : Begin (
const FRDGEventName & InGraphName ,
const FRDGPassRegistry * InPasses ,
2020-09-24 00:43:27 -04:00
FRDGPassBitArray InPassesCulled ,
2020-07-06 18:58:26 -04:00
FRDGPassHandle InProloguePassHandle ,
FRDGPassHandle InEpiloguePassHandle )
{
if ( GRDGDumpGraph )
{
if ( GRDGImmediateMode )
{
UE_LOG ( LogRDG , Warning , TEXT ( " Dump graph (%d) requested, but immediate mode is enabled. Skipping. " ) , GRDGDumpGraph ) ;
return ;
}
check ( File . IsEmpty ( ) ) ;
check ( InPasses & & InEpiloguePassHandle . IsValid ( ) ) ;
Passes = InPasses ;
2020-09-24 00:43:27 -04:00
PassesCulled = InPassesCulled ;
2020-07-06 18:58:26 -04:00
ProloguePassHandle = InProloguePassHandle ;
EpiloguePassHandle = InEpiloguePassHandle ;
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 ;
for ( FRDGPassHandle PassHandle = Passes - > Begin ( ) ; PassHandle ! = Passes - > End ( ) ; + + PassHandle )
{
const FRDGPass * Pass = Passes - > Get ( 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
for ( FRDGPassHandle PassHandle = Passes - > Begin ( ) ; PassHandle ! = Passes - > End ( ) ; + + PassHandle )
{
const FRDGPass * Pass = Passes - > Get ( PassHandle ) ;
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
{
for ( FRDGPassHandle PassHandle = Passes - > Begin ( ) ; PassHandle ! = Passes - > End ( ) ; + + PassHandle )
{
if ( PassHandle = = EpiloguePassHandle )
{
break ;
}
const FRDGPass * Pass = Passes - > Get ( PassHandle ) ;
2020-10-29 13:38:15 -04:00
for ( FRDGPassHandle ProducerHandle : Pass - > GetProducers ( ) )
2020-07-06 18:58:26 -04:00
{
if ( ProducerHandle ! = ProloguePassHandle )
{
const FRDGPass * Producer = Passes - > Get ( ProducerHandle ) ;
File + = FString : : Printf ( TEXT ( " \t \" %s \" -> \" %s \" [penwidth=2, color= \" %s:%s \" ] \n " ) ,
* GetNodeName ( ProducerHandle ) , * GetNodeName ( PassHandle ) , GetPassColorName ( Pass - > GetFlags ( ) ) , GetPassColorName ( Producer - > GetFlags ( ) ) ) ;
}
}
}
}
AddLine ( TEXT ( " subgraph Passes " ) ) ;
AddBraceBegin ( ) ;
const auto AddPass = [ & ] ( FRDGPassHandle PassHandle )
{
if ( ! PassesReferenced . Contains ( PassHandle ) )
{
return ;
}
const FRDGPass * Pass = Passes - > Get ( PassHandle ) ;
2020-09-24 00:43:27 -04:00
const TCHAR * Style = PassesCulled [ PassHandle ] ? 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 )
{
const FRDGPass * Pass = Passes - > Get ( PassHandle ) ;
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 ;
for ( FRDGPassHandle PassHandle = Passes - > Begin ( ) ; PassHandle ! = Passes - > End ( ) ; + + PassHandle )
{
if ( PassesCulled [ PassHandle ] )
{
NumPassesCulled + + ;
}
else
{
NumPassesActive + + ;
}
}
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
{
return Pass . IsValid ( ) & & Pass ! = ProloguePassHandle & & Pass ! = EpiloguePassHandle ;
}
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 )
{
2020-09-24 00:43:27 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( FirstPass ) )
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 )
{
2020-09-24 00:43:27 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( FirstPass ) )
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
{
2020-09-24 00:43:27 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( BeforePass , AfterPass ) )
{
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 )
{
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( BeforePass , AfterPass ) )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<Alias: <b>%s -> %s</b>>] " ) ,
* GetProducerName ( BeforePass ) ,
* GetConsumerName ( AfterPass ) ,
AliasColorAttributes ,
BufferBefore - > Name ,
BufferAfter - > Name ) ) ;
}
}
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , FRDGSubresourceState StateBefore , FRDGSubresourceState StateAfter , const FRDGTextureRef Texture )
{
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( StateBefore . FirstPass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
if ( FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s -> %s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . LastPass ) ,
* GetConsumerName ( StateAfter . FirstPass ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ,
* GetSubresourceStateLabel ( StateAfter ) ) ) ;
}
else
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . FirstPass ) ,
* GetConsumerName ( PassHandle ) ,
2020-07-06 18:58:26 -04:00
TextureColorAttributes ,
Texture - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ) ) ;
}
}
}
2020-09-24 00:43:27 -04:00
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , FRDGSubresourceState StateBefore , FRDGSubresourceState StateAfter , const FRDGTextureRef Texture , FRDGTextureSubresource Subresource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( StateBefore . FirstPass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
if ( FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s[%d][%d][%d]: <b>%s -> %s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . LastPass ) ,
* GetConsumerName ( StateAfter . FirstPass ) ,
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 ) ) ) ;
}
else
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s[%d][%d][%d]: <b>%s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . FirstPass ) ,
* 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 ) ) ) ;
}
}
}
2020-09-24 00:43:27 -04:00
void FRDGLogFile : : AddTransitionEdge ( FRDGPassHandle PassHandle , FRDGSubresourceState StateBefore , FRDGSubresourceState StateAfter , const FRDGBufferRef Buffer )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( GRDGDumpGraph = = RDG_DUMP_GRAPH_RESOURCES & & bOpen & & IncludeTransitionEdgeInGraph ( StateBefore . FirstPass , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
if ( FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s -> %s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . LastPass ) ,
* GetConsumerName ( StateAfter . FirstPass ) ,
2020-07-06 18:58:26 -04:00
BufferColorAttributes ,
Buffer - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ,
* GetSubresourceStateLabel ( StateAfter ) ) ) ;
}
else
{
AddLine ( FString : : Printf ( TEXT ( " \" %s \" -> \" %s \" [%s, label=<%s: <b>%s</b>>] " ) ,
2020-09-24 00:43:27 -04:00
* GetProducerName ( StateBefore . FirstPass ) ,
* GetConsumerName ( PassHandle ) ,
2020-07-06 18:58:26 -04:00
BufferColorAttributes ,
Buffer - > Name ,
* GetSubresourceStateLabel ( StateBefore ) ) ) ;
}
}
}
2020-10-29 13:38:15 -04:00
# endif