2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
# include "RenderGraphBuilder.h"
2020-07-06 18:58:26 -04:00
# include "RenderGraphPrivate.h"
2021-02-03 13:17:04 -04:00
# include "RenderGraphTrace.h"
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
# include "RenderTargetPool.h"
2018-10-22 23:01:29 -04:00
# include "RenderGraphResourcePool.h"
2018-11-21 20:22:47 -05:00
# include "VisualizeTexture.h"
2019-04-12 10:05:47 -04:00
# include "ProfilingDebugging/CsvProfiler.h"
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2021-12-03 16:04:00 -05:00
2021-02-24 18:07:36 -04:00
# if ENABLE_RHI_VALIDATION
inline void GatherPassUAVsForOverlapValidation ( const FRDGPass * Pass , TArray < FRHIUnorderedAccessView * , TInlineAllocator < MaxSimultaneousUAVs , FRDGArrayAllocator > > & OutUAVs )
2020-11-30 13:41:01 -04:00
{
2021-02-24 18:07:36 -04:00
// RHI validation tracking of Begin/EndUAVOverlaps happens on the underlying resource, so we need to be careful about not
// passing multiple UAVs that refer to the same resource, otherwise we get double-Begin and double-End validation errors.
// Filter UAVs to only those with unique parent resources.
2022-03-25 11:19:10 -04:00
TArray < FRDGViewableResource * , TInlineAllocator < MaxSimultaneousUAVs , FRDGArrayAllocator > > UniqueParents ;
2020-11-30 13:41:01 -04:00
Pass - > GetParameters ( ) . Enumerate ( [ & ] ( FRDGParameter Parameter )
{
if ( Parameter . IsUAV ( ) )
{
if ( FRDGUnorderedAccessViewRef UAV = Parameter . GetAsUAV ( ) )
{
2022-03-25 11:19:10 -04:00
FRDGViewableResource * Parent = UAV - > GetParent ( ) ;
2021-02-24 18:07:36 -04:00
// Check if we've already seen this parent.
bool bFound = false ;
for ( int32 Index = 0 ; ! bFound & & Index < UniqueParents . Num ( ) ; + + Index )
{
bFound = UniqueParents [ Index ] = = Parent ;
}
if ( ! bFound )
{
UniqueParents . Add ( Parent ) ;
OutUAVs . Add ( UAV - > GetRHI ( ) ) ;
}
2020-11-30 13:41:01 -04:00
}
}
} ) ;
}
2021-02-24 18:07:36 -04:00
# endif
2020-11-30 13:41:01 -04:00
inline void BeginUAVOverlap ( const FRDGPass * Pass , FRHIComputeCommandList & RHICmdList )
{
# if ENABLE_RHI_VALIDATION
2021-02-24 18:07:36 -04:00
TArray < FRHIUnorderedAccessView * , TInlineAllocator < MaxSimultaneousUAVs , FRDGArrayAllocator > > UAVs ;
GatherPassUAVsForOverlapValidation ( Pass , UAVs ) ;
if ( UAVs . Num ( ) )
2020-11-30 13:41:01 -04:00
{
2021-02-24 18:07:36 -04:00
RHICmdList . BeginUAVOverlap ( UAVs ) ;
}
2020-11-30 13:41:01 -04:00
# endif
}
inline void EndUAVOverlap ( const FRDGPass * Pass , FRHIComputeCommandList & RHICmdList )
{
# if ENABLE_RHI_VALIDATION
2021-02-24 18:07:36 -04:00
TArray < FRHIUnorderedAccessView * , TInlineAllocator < MaxSimultaneousUAVs , FRDGArrayAllocator > > UAVs ;
GatherPassUAVsForOverlapValidation ( Pass , UAVs ) ;
if ( UAVs . Num ( ) )
2020-11-30 13:41:01 -04:00
{
2021-02-24 18:07:36 -04:00
RHICmdList . EndUAVOverlap ( UAVs ) ;
}
2020-11-30 13:41:01 -04:00
# endif
}
2020-09-24 00:43:27 -04:00
inline ERHIAccess MakeValidAccess ( ERHIAccess Access )
2019-06-11 18:27:07 -04:00
{
2020-09-24 00:43:27 -04:00
// If we find any write states in the access mask, remove all read-only states. This mainly exists
// to allow RDG uniform buffers to contain read-only parameters which are also bound for write on the
// pass. Often times these uniform buffers are created and only relevant things are accessed. If an
// invalid access does occur, the RHI validation layer will catch it.
return IsWritableAccess ( Access ) ? ( Access & ~ ERHIAccess : : ReadOnlyExclusiveMask ) : Access ;
2020-07-06 18:58:26 -04:00
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-09-24 00:43:27 -04:00
inline void GetPassAccess ( ERDGPassFlags PassFlags , ERHIAccess & SRVAccess , ERHIAccess & UAVAccess )
2019-08-15 18:58:08 -04:00
{
2020-09-24 00:43:27 -04:00
SRVAccess = ERHIAccess : : Unknown ;
UAVAccess = ERHIAccess : : Unknown ;
2020-07-06 18:58:26 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Raster ) )
2019-08-15 18:58:08 -04:00
{
2021-03-05 19:27:14 -04:00
SRVAccess | = ERHIAccess : : SRVGraphics ;
2020-09-24 00:43:27 -04:00
UAVAccess | = ERHIAccess : : UAVGraphics ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : AsyncCompute | ERDGPassFlags : : Compute ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
SRVAccess | = ERHIAccess : : SRVCompute ;
UAVAccess | = ERHIAccess : : UAVCompute ;
2020-07-06 18:58:26 -04:00
}
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Copy ) )
{
2020-09-24 00:43:27 -04:00
SRVAccess | = ERHIAccess : : CopySrc ;
2019-08-15 18:58:08 -04:00
}
}
2021-03-17 12:44:59 -04:00
enum class ERDGTextureAccessFlags
{
None = 0 ,
// Access is within the fixed-function render pass.
RenderTarget = 1 < < 0
} ;
ENUM_CLASS_FLAGS ( ERDGTextureAccessFlags ) ;
2020-07-06 18:58:26 -04:00
/** Enumerates all texture accesses and provides the access and subresource range info. This results in
* multiple invocations of the same resource , but with different access / subresource range .
*/
template < typename TAccessFunction >
2020-09-24 00:43:27 -04:00
void EnumerateTextureAccess ( FRDGParameterStruct PassParameters , ERDGPassFlags PassFlags , TAccessFunction AccessFunction )
2019-08-15 18:58:08 -04:00
{
2021-03-17 12:44:59 -04:00
const ERDGTextureAccessFlags NoneFlags = ERDGTextureAccessFlags : : None ;
2020-09-24 00:43:27 -04:00
ERHIAccess SRVAccess , UAVAccess ;
2020-07-06 18:58:26 -04:00
GetPassAccess ( PassFlags , SRVAccess , UAVAccess ) ;
2019-06-11 20:13:27 -04:00
2020-09-24 00:43:27 -04:00
PassParameters . EnumerateTextures ( [ & ] ( FRDGParameter Parameter )
2018-12-18 21:41:17 -05:00
{
2020-07-06 18:58:26 -04:00
switch ( Parameter . GetType ( ) )
2019-06-11 18:27:07 -04:00
{
2020-07-06 18:58:26 -04:00
case UBMT_RDG_TEXTURE :
if ( FRDGTextureRef Texture = Parameter . GetAsTexture ( ) )
2019-06-11 20:13:27 -04:00
{
2021-03-17 12:44:59 -04:00
AccessFunction ( nullptr , Texture , SRVAccess , NoneFlags , Texture - > GetSubresourceRangeSRV ( ) ) ;
2020-07-06 18:58:26 -04:00
}
break ;
2020-09-24 00:43:27 -04:00
case UBMT_RDG_TEXTURE_ACCESS :
{
if ( FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) )
2020-07-06 18:58:26 -04:00
{
2021-04-02 20:35:50 -04:00
AccessFunction ( nullptr , TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) , NoneFlags , TextureAccess - > GetSubresourceRange ( ) ) ;
}
}
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
AccessFunction ( nullptr , TextureAccess . GetTexture ( ) , TextureAccess . GetAccess ( ) , NoneFlags , TextureAccess - > GetSubresourceRange ( ) ) ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
break ;
case UBMT_RDG_TEXTURE_SRV :
if ( FRDGTextureSRVRef SRV = Parameter . GetAsTextureSRV ( ) )
{
2021-03-17 12:44:59 -04:00
AccessFunction ( SRV , SRV - > GetParent ( ) , SRVAccess , NoneFlags , SRV - > GetSubresourceRange ( ) ) ;
2020-07-06 18:58:26 -04:00
}
break ;
case UBMT_RDG_TEXTURE_UAV :
if ( FRDGTextureUAVRef UAV = Parameter . GetAsTextureUAV ( ) )
{
2021-03-17 12:44:59 -04:00
AccessFunction ( UAV , UAV - > GetParent ( ) , UAVAccess , NoneFlags , UAV - > GetSubresourceRange ( ) ) ;
2020-07-06 18:58:26 -04:00
}
break ;
case UBMT_RENDER_TARGET_BINDING_SLOTS :
{
2021-03-17 12:44:59 -04:00
const ERDGTextureAccessFlags RenderTargetAccess = ERDGTextureAccessFlags : : RenderTarget ;
2020-09-24 00:43:27 -04:00
const ERHIAccess RTVAccess = ERHIAccess : : RTV ;
2020-07-06 18:58:26 -04:00
const FRenderTargetBindingSlots & RenderTargets = Parameter . GetAsRenderTargetBindingSlots ( ) ;
RenderTargets . Enumerate ( [ & ] ( FRenderTargetBinding RenderTarget )
{
FRDGTextureRef Texture = RenderTarget . GetTexture ( ) ;
2020-09-24 00:43:27 -04:00
FRDGTextureRef ResolveTexture = RenderTarget . GetResolveTexture ( ) ;
2020-07-06 18:58:26 -04:00
FRDGTextureSubresourceRange Range ( Texture - > GetSubresourceRange ( ) ) ;
Range . MipIndex = RenderTarget . GetMipIndex ( ) ;
Range . NumMips = 1 ;
if ( RenderTarget . GetArraySlice ( ) ! = - 1 )
{
Range . ArraySlice = RenderTarget . GetArraySlice ( ) ;
Range . NumArraySlices = 1 ;
}
2021-03-17 12:44:59 -04:00
AccessFunction ( nullptr , Texture , RTVAccess , RenderTargetAccess , Range ) ;
2020-09-24 00:43:27 -04:00
if ( ResolveTexture & & ResolveTexture ! = Texture )
{
// Resolve targets must use the RTV|ResolveDst flag combination when the resolve is performed through the render
// pass. The ResolveDst flag must be used alone only when the resolve is performed using RHICopyToResolveTarget.
2021-03-17 12:44:59 -04:00
AccessFunction ( nullptr , ResolveTexture , ERHIAccess : : RTV | ERHIAccess : : ResolveDst , RenderTargetAccess , Range ) ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
const FDepthStencilBinding & DepthStencil = RenderTargets . DepthStencil ;
if ( FRDGTextureRef Texture = DepthStencil . GetTexture ( ) )
{
2020-09-24 00:43:27 -04:00
DepthStencil . GetDepthStencilAccess ( ) . EnumerateSubresources ( [ & ] ( ERHIAccess NewAccess , uint32 PlaneSlice )
2020-07-06 18:58:26 -04:00
{
FRDGTextureSubresourceRange Range = Texture - > GetSubresourceRange ( ) ;
// Adjust the range to use a single plane slice if not using of them all.
if ( PlaneSlice ! = FRHITransitionInfo : : kAllSubresources )
{
Range . PlaneSlice = PlaneSlice ;
Range . NumPlaneSlices = 1 ;
}
2021-03-17 12:44:59 -04:00
AccessFunction ( nullptr , Texture , NewAccess , RenderTargetAccess , Range ) ;
2020-07-06 18:58:26 -04:00
} ) ;
2019-06-11 20:13:27 -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
{
2021-04-08 14:32:07 -04:00
AccessFunction ( nullptr , Texture , ERHIAccess : : ShadingRateSource , RenderTargetAccess , Texture - > GetSubresourceRangeSRV ( ) ) ;
2021-03-05 16:16:14 -04:00
}
2019-06-11 18:27:07 -04:00
}
2020-07-06 18:58:26 -04:00
break ;
}
2020-09-24 00:43:27 -04:00
} ) ;
2020-07-06 18:58:26 -04:00
}
/** Enumerates all buffer accesses and provides the access info. */
template < typename TAccessFunction >
2020-09-24 00:43:27 -04:00
void EnumerateBufferAccess ( FRDGParameterStruct PassParameters , ERDGPassFlags PassFlags , TAccessFunction AccessFunction )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
ERHIAccess SRVAccess , UAVAccess ;
2020-07-06 18:58:26 -04:00
GetPassAccess ( PassFlags , SRVAccess , UAVAccess ) ;
2020-09-24 00:43:27 -04:00
PassParameters . EnumerateBuffers ( [ & ] ( FRDGParameter Parameter )
2020-07-06 18:58:26 -04:00
{
switch ( Parameter . GetType ( ) )
{
2020-09-24 00:43:27 -04:00
case UBMT_RDG_BUFFER_ACCESS :
if ( FRDGBufferAccess BufferAccess = Parameter . GetAsBufferAccess ( ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
AccessFunction ( nullptr , BufferAccess . GetBuffer ( ) , BufferAccess . GetAccess ( ) ) ;
2020-07-06 18:58:26 -04:00
}
break ;
2021-04-02 20:35:50 -04:00
case UBMT_RDG_BUFFER_ACCESS_ARRAY :
{
const FRDGBufferAccessArray & BufferAccessArray = Parameter . GetAsBufferAccessArray ( ) ;
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
AccessFunction ( nullptr , BufferAccess . GetBuffer ( ) , BufferAccess . GetAccess ( ) ) ;
2021-04-02 20:35:50 -04:00
}
}
break ;
2020-07-06 18:58:26 -04:00
case UBMT_RDG_BUFFER_SRV :
if ( FRDGBufferSRVRef SRV = Parameter . GetAsBufferSRV ( ) )
{
2021-03-25 06:36:58 -04:00
FRDGBufferRef Buffer = SRV - > GetParent ( ) ;
ERHIAccess BufferAccess = SRVAccess ;
if ( EnumHasAnyFlags ( Buffer - > Desc . Usage , BUF_AccelerationStructure ) )
{
BufferAccess = ERHIAccess : : BVHRead ;
}
AccessFunction ( SRV , Buffer , BufferAccess ) ;
2020-07-06 18:58:26 -04:00
}
break ;
case UBMT_RDG_BUFFER_UAV :
if ( FRDGBufferUAVRef UAV = Parameter . GetAsBufferUAV ( ) )
{
AccessFunction ( UAV , UAV - > GetParent ( ) , UAVAccess ) ;
}
break ;
}
2020-09-24 00:43:27 -04:00
} ) ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
inline FRDGViewHandle GetHandleIfNoUAVBarrier ( FRDGViewRef Resource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( Resource & & ( Resource - > Type = = ERDGViewType : : BufferUAV | | Resource - > Type = = ERDGViewType : : TextureUAV ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( EnumHasAnyFlags ( static_cast < FRDGUnorderedAccessViewRef > ( Resource ) - > Flags , ERDGUnorderedAccessViewFlags : : SkipBarrier ) )
{
return Resource - > GetHandle ( ) ;
}
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
return FRDGViewHandle : : Null ;
2020-07-06 18:58:26 -04:00
}
2019-08-15 18:58:08 -04:00
2020-10-09 22:42:26 -04:00
inline EResourceTransitionFlags GetTextureViewTransitionFlags ( FRDGViewRef Resource , FRDGTextureRef Texture )
2020-07-06 18:58:26 -04:00
{
if ( Resource )
{
switch ( Resource - > Type )
2019-06-11 20:13:27 -04:00
{
2020-09-24 00:43:27 -04:00
case ERDGViewType : : TextureUAV :
2020-07-06 18:58:26 -04:00
{
FRDGTextureUAVRef UAV = static_cast < FRDGTextureUAVRef > ( Resource ) ;
if ( UAV - > Desc . MetaData ! = ERDGTextureMetaDataAccess : : None )
{
return EResourceTransitionFlags : : MaintainCompression ;
}
}
break ;
2020-09-24 00:43:27 -04:00
case ERDGViewType : : TextureSRV :
2020-07-06 18:58:26 -04:00
{
FRDGTextureSRVRef SRV = static_cast < FRDGTextureSRVRef > ( Resource ) ;
if ( SRV - > Desc . MetaData ! = ERDGTextureMetaDataAccess : : None )
{
return EResourceTransitionFlags : : MaintainCompression ;
}
}
break ;
2019-06-11 20:13:27 -04:00
}
2019-01-16 15:48:28 -05:00
}
2020-10-09 22:42:26 -04:00
else
{
if ( EnumHasAnyFlags ( Texture - > Flags , ERDGTextureFlags : : MaintainCompression ) )
{
return EResourceTransitionFlags : : MaintainCompression ;
}
}
2020-07-06 18:58:26 -04:00
return EResourceTransitionFlags : : None ;
2019-01-16 15:48:28 -05:00
}
2021-07-13 12:38:37 -04:00
void FRDGBuilder : : SetFlushResourcesRHI ( )
{
if ( GRHINeedsExtraDeletionLatency | | ! GRHICommandList . Bypass ( ) )
{
checkf ( ! bFlushResourcesRHI , TEXT ( " SetFlushRHIResources has been already been called. It may only be called once. " ) ) ;
bFlushResourcesRHI = true ;
if ( IsImmediateMode ( ) )
{
BeginFlushResourcesRHI ( ) ;
EndFlushResourcesRHI ( ) ;
}
}
}
void FRDGBuilder : : BeginFlushResourcesRHI ( )
{
2022-01-31 15:55:31 -05:00
if ( ! bFlushResourcesRHI )
2021-07-13 12:38:37 -04:00
{
return ;
}
CSV_SCOPED_TIMING_STAT_EXCLUSIVE ( STAT_RDG_FlushResourcesRHI ) ;
SCOPED_NAMED_EVENT ( BeginFlushResourcesRHI , FColor : : Emerald ) ;
RHICmdList . ImmediateFlush ( EImmediateFlushType : : DispatchToRHIThread ) ;
}
void FRDGBuilder : : EndFlushResourcesRHI ( )
{
2022-01-31 15:55:31 -05:00
if ( ! bFlushResourcesRHI )
2021-07-13 12:38:37 -04:00
{
return ;
}
CSV_SCOPED_TIMING_STAT_EXCLUSIVE ( STAT_RDG_FlushResourcesRHI ) ;
SCOPED_NAMED_EVENT ( EndFlushResourcesRHI , FColor : : Emerald ) ;
RHICmdList . WaitForDispatch ( ) ;
RHICmdList . WaitForRHIThreadTasks ( ) ;
RHICmdList . WaitForTasks ( true /* bKnownToBeComplete */ ) ;
PipelineStateCache : : FlushResources ( ) ;
FRHIResource : : FlushPendingDeletes ( RHICmdList ) ;
}
2019-07-09 17:22:17 -04:00
void FRDGBuilder : : TickPoolElements ( )
{
GRenderGraphResourcePool . TickPoolElements ( ) ;
2020-07-06 18:58:26 -04:00
# if RDG_ENABLE_DEBUG
if ( GRDGDumpGraph )
{
- - GRDGDumpGraph ;
}
if ( GRDGTransitionLog > 0 )
{
- - GRDGTransitionLog ;
}
GRDGDumpGraphUnknownCount = 0 ;
# endif
2020-09-24 00:43:27 -04:00
# if STATS
SET_DWORD_STAT ( STAT_RDG_PassCount , GRDGStatPassCount ) ;
2020-11-11 19:22:36 -04:00
SET_DWORD_STAT ( STAT_RDG_PassWithParameterCount , GRDGStatPassWithParameterCount ) ;
2020-09-24 00:43:27 -04:00
SET_DWORD_STAT ( STAT_RDG_PassCullCount , GRDGStatPassCullCount ) ;
SET_DWORD_STAT ( STAT_RDG_RenderPassMergeCount , GRDGStatRenderPassMergeCount ) ;
SET_DWORD_STAT ( STAT_RDG_PassDependencyCount , GRDGStatPassDependencyCount ) ;
SET_DWORD_STAT ( STAT_RDG_TextureCount , GRDGStatTextureCount ) ;
2021-05-05 11:58:15 -04:00
SET_DWORD_STAT ( STAT_RDG_TextureReferenceCount , GRDGStatTextureReferenceCount ) ;
2022-01-07 10:39:08 -05:00
SET_FLOAT_STAT ( STAT_RDG_TextureReferenceAverage , ( float ) ( GRDGStatTextureReferenceCount / FMath : : Max ( ( float ) GRDGStatTextureCount , 1.0f ) ) ) ;
2020-09-24 00:43:27 -04:00
SET_DWORD_STAT ( STAT_RDG_BufferCount , GRDGStatBufferCount ) ;
2021-05-05 11:58:15 -04:00
SET_DWORD_STAT ( STAT_RDG_BufferReferenceCount , GRDGStatBufferReferenceCount ) ;
2022-01-07 10:39:08 -05:00
SET_FLOAT_STAT ( STAT_RDG_BufferReferenceAverage , ( float ) ( GRDGStatBufferReferenceCount / FMath : : Max ( ( float ) GRDGStatBufferCount , 1.0f ) ) ) ;
2021-05-05 11:58:15 -04:00
SET_DWORD_STAT ( STAT_RDG_ViewCount , GRDGStatViewCount ) ;
2021-03-17 12:44:59 -04:00
SET_DWORD_STAT ( STAT_RDG_TransientTextureCount , GRDGStatTransientTextureCount ) ;
SET_DWORD_STAT ( STAT_RDG_TransientBufferCount , GRDGStatTransientBufferCount ) ;
2020-09-24 00:43:27 -04:00
SET_DWORD_STAT ( STAT_RDG_TransitionCount , GRDGStatTransitionCount ) ;
2021-03-17 12:44:59 -04:00
SET_DWORD_STAT ( STAT_RDG_AliasingCount , GRDGStatAliasingCount ) ;
2020-09-24 00:43:27 -04:00
SET_DWORD_STAT ( STAT_RDG_TransitionBatchCount , GRDGStatTransitionBatchCount ) ;
SET_MEMORY_STAT ( STAT_RDG_MemoryWatermark , int64 ( GRDGStatMemoryWatermark ) ) ;
GRDGStatPassCount = 0 ;
2020-11-11 19:22:36 -04:00
GRDGStatPassWithParameterCount = 0 ;
2020-09-24 00:43:27 -04:00
GRDGStatPassCullCount = 0 ;
GRDGStatRenderPassMergeCount = 0 ;
GRDGStatPassDependencyCount = 0 ;
GRDGStatTextureCount = 0 ;
2021-05-05 11:58:15 -04:00
GRDGStatTextureReferenceCount = 0 ;
2020-09-24 00:43:27 -04:00
GRDGStatBufferCount = 0 ;
2021-05-05 11:58:15 -04:00
GRDGStatBufferReferenceCount = 0 ;
GRDGStatViewCount = 0 ;
2021-03-17 12:44:59 -04:00
GRDGStatTransientTextureCount = 0 ;
GRDGStatTransientBufferCount = 0 ;
2020-09-24 00:43:27 -04:00
GRDGStatTransitionCount = 0 ;
2021-03-17 12:44:59 -04:00
GRDGStatAliasingCount = 0 ;
2020-09-24 00:43:27 -04:00
GRDGStatTransitionBatchCount = 0 ;
GRDGStatMemoryWatermark = 0 ;
# endif
2019-07-09 17:22:17 -04:00
}
2021-06-07 12:19:06 -04:00
bool FRDGBuilder : : IsImmediateMode ( )
{
return : : IsImmediateMode ( ) ;
}
2020-07-06 18:58:26 -04:00
ERDGPassFlags FRDGBuilder : : OverridePassFlags ( const TCHAR * PassName , ERDGPassFlags PassFlags , bool bAsyncComputeSupported )
{
const bool bDebugAllowedForPass =
# if RDG_ENABLE_DEBUG
IsDebugAllowedForPass ( PassName ) ;
# else
true ;
# endif
2021-03-17 12:44:59 -04:00
const bool bGlobalForceAsyncCompute = ( GRDGAsyncCompute = = RDG_ASYNC_COMPUTE_FORCE_ENABLED & & ! IsImmediateMode ( ) & & bDebugAllowedForPass ) ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Compute ) & & ( bGlobalForceAsyncCompute ) )
2020-07-06 18:58:26 -04:00
{
PassFlags & = ~ ERDGPassFlags : : Compute ;
PassFlags | = ERDGPassFlags : : AsyncCompute ;
}
2021-03-17 12:44:59 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : AsyncCompute ) & & ( GRDGAsyncCompute = = RDG_ASYNC_COMPUTE_DISABLED | | IsImmediateMode ( ) | | ! bAsyncComputeSupported ) )
2020-07-06 18:58:26 -04:00
{
PassFlags & = ~ ERDGPassFlags : : AsyncCompute ;
PassFlags | = ERDGPassFlags : : Compute ;
}
return PassFlags ;
}
2021-03-17 12:44:59 -04:00
bool FRDGBuilder : : IsTransient ( FRDGBufferRef Buffer ) const
{
2022-01-12 14:29:07 -05:00
if ( ! IsTransientInternal ( Buffer , EnumHasAnyFlags ( Buffer - > Desc . Usage , BUF_FastVRAM ) ) )
2021-03-17 12:44:59 -04:00
{
return false ;
}
2021-05-21 17:42:34 -04:00
if ( ! GRDGTransientIndirectArgBuffers & & EnumHasAnyFlags ( Buffer - > Desc . Usage , BUF_DrawIndirect ) )
{
return false ;
}
2021-04-21 13:03:28 -04:00
return EnumHasAnyFlags ( Buffer - > Desc . Usage , BUF_UnorderedAccess ) ;
2021-03-17 12:44:59 -04:00
}
bool FRDGBuilder : : IsTransient ( FRDGTextureRef Texture ) const
{
2022-01-12 14:29:07 -05:00
return IsTransientInternal ( Texture , EnumHasAnyFlags ( Texture - > Desc . Flags , ETextureCreateFlags : : FastVRAM ) ) ;
2021-03-17 12:44:59 -04:00
}
2022-03-25 11:19:10 -04:00
bool FRDGBuilder : : IsTransientInternal ( FRDGViewableResource * Resource , bool bFastVRAM ) const
2021-03-17 12:44:59 -04:00
{
// Immediate mode can't use the transient allocator because we don't know if the user will extract the resource.
if ( ! GRDGTransientAllocator | | IsImmediateMode ( ) )
{
return false ;
}
2022-01-12 14:29:07 -05:00
// FastVRAM resources are always transient regardless of extraction or other hints, since they are performance critical.
2022-01-12 19:38:45 -05:00
if ( ! bFastVRAM | | ! FPlatformMemory : : SupportsFastVRAMMemory ( ) )
2021-03-17 12:44:59 -04:00
{
2022-01-12 14:29:07 -05:00
if ( GRDGTransientAllocator = = 2 )
{
return false ;
}
if ( Resource - > bForceNonTransient )
2022-01-03 18:28:16 -05:00
{
return false ;
}
2022-01-12 14:29:07 -05:00
if ( Resource - > bExtracted )
2022-01-03 18:28:16 -05:00
{
2022-01-12 14:29:07 -05:00
if ( GRDGTransientExtractedResources = = 0 )
{
return false ;
}
2022-03-25 11:19:10 -04:00
if ( GRDGTransientExtractedResources = = 1 & & Resource - > TransientExtractionHint = = FRDGViewableResource : : ETransientExtractionHint : : Disable )
2022-01-12 14:29:07 -05:00
{
return false ;
}
2022-01-03 18:28:16 -05:00
}
}
2021-04-21 13:03:28 -04:00
# if RDG_ENABLE_DEBUG
if ( GRDGDebugDisableTransientResources ! = 0 & & IsDebugAllowedForResource ( Resource - > Name ) )
{
return false ;
}
# endif
2021-03-17 12:44:59 -04:00
return true ;
}
2021-07-22 12:43:00 -04:00
FRDGBuilder : : FRDGBuilder ( FRHICommandListImmediate & InRHICmdList , FRDGEventName InName , ERDGBuilderFlags InFlags )
2019-06-11 18:27:07 -04:00
: RHICmdList ( InRHICmdList )
2020-11-17 23:33:02 -04:00
, Blackboard ( Allocator )
2020-11-18 18:25:03 -04:00
, RHICmdListAsyncCompute ( FRHICommandListExecutor : : GetImmediateAsyncComputeCommandList ( ) )
2020-09-24 00:43:27 -04:00
, BuilderName ( InName )
# if RDG_CPU_SCOPES
2021-07-13 12:38:37 -04:00
, CPUScopeStacks ( Allocator )
2020-09-24 00:43:27 -04:00
# endif
# if RDG_GPU_SCOPES
2021-07-13 12:38:37 -04:00
, GPUScopeStacks ( Allocator )
2020-07-06 18:58:26 -04:00
# endif
2021-07-22 12:43:00 -04:00
, bParallelExecuteEnabled ( IsParallelExecuteEnabled ( ) & & EnumHasAnyFlags ( InFlags , ERDGBuilderFlags : : AllowParallelExecute ) )
2020-07-06 18:58:26 -04:00
# if RDG_ENABLE_DEBUG
2021-07-29 13:02:16 -04:00
, UserValidation ( Allocator , bParallelExecuteEnabled )
2020-07-06 18:58:26 -04:00
, BarrierValidation ( & Passes , BuilderName )
# endif
2022-01-03 18:28:16 -05:00
, TransientResourceAllocator ( GRDGTransientResourceAllocator . Get ( ) )
2020-03-25 13:21:18 -04:00
{
2021-05-19 17:54:58 -04:00
AddProloguePass ( ) ;
2021-03-22 12:51:37 -04:00
# if RDG_EVENTS != RDG_EVENTS_NONE
// This is polled once as a workaround for a race condition since the underlying global is not always changed on the render thread.
GRDGEmitEvents = GetEmitDrawEvents ( ) ;
# endif
2021-05-19 17:54:58 -04:00
2021-10-12 21:21:22 -04:00
# if RHI_WANT_BREADCRUMB_EVENTS
if ( bParallelExecuteEnabled )
{
BreadcrumbState = FRDGBreadcrumbState : : Create ( Allocator ) ;
}
# endif
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
2021-07-13 12:38:37 -04:00
FRDGBuilder : : ~ FRDGBuilder ( )
{
SCOPED_NAMED_EVENT ( FRDGBuilder_Clear , FColor : : Emerald ) ;
Passes . Clear ( ) ;
Buffers . Clear ( ) ;
UniformBuffers . Clear ( ) ;
Blackboard . Clear ( ) ;
ActivePooledTextures . Empty ( ) ;
ActivePooledBuffers . Empty ( ) ;
}
2021-05-19 17:54:58 -04:00
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-04-06 11:45:09 -04:00
const TRefCountPtr < FRDGPooledBuffer > & FRDGBuilder : : ConvertToExternalBuffer ( FRDGBufferRef Buffer )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateConvertToExternalResource ( Buffer ) ) ;
2020-09-24 00:43:27 -04:00
if ( ! Buffer - > bExternal )
{
Buffer - > bExternal = 1 ;
2022-01-03 18:28:16 -05:00
Buffer - > bForceNonTransient = 1 ;
2021-05-19 17:54:58 -04:00
BeginResourceRHI ( GetProloguePassHandle ( ) , Buffer ) ;
2022-04-22 17:11:57 -04:00
ExternalBuffers . Add ( Buffer - > GetRHIUnchecked ( ) , Buffer ) ;
2020-09-24 00:43:27 -04:00
}
2021-04-06 11:45:09 -04:00
return GetPooledBuffer ( Buffer ) ;
2020-09-24 00:43:27 -04:00
}
2021-04-06 11:45:09 -04:00
const TRefCountPtr < IPooledRenderTarget > & FRDGBuilder : : ConvertToExternalTexture ( FRDGTextureRef Texture )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateConvertToExternalResource ( Texture ) ) ;
2020-09-24 00:43:27 -04:00
if ( ! Texture - > bExternal )
{
Texture - > bExternal = 1 ;
2022-01-03 18:28:16 -05:00
Texture - > bForceNonTransient = 1 ;
2021-05-19 17:54:58 -04:00
BeginResourceRHI ( GetProloguePassHandle ( ) , Texture ) ;
2020-09-24 00:43:27 -04:00
ExternalTextures . Add ( Texture - > GetRHIUnchecked ( ) , Texture ) ;
}
2021-04-06 11:45:09 -04:00
return GetPooledTexture ( Texture ) ;
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2022-04-25 13:00:12 -04:00
BEGIN_SHADER_PARAMETER_STRUCT ( FAccessModePassParameters , )
2021-04-06 11:45:09 -04:00
RDG_TEXTURE_ACCESS_ARRAY ( Textures )
RDG_BUFFER_ACCESS_ARRAY ( Buffers )
END_SHADER_PARAMETER_STRUCT ( )
2022-04-25 13:00:12 -04:00
void FRDGBuilder : : UseExternalAccessMode ( FRDGViewableResource * Resource , ERHIAccess ReadOnlyAccess , ERHIPipeline Pipelines )
2021-04-06 11:45:09 -04:00
{
2022-05-02 18:31:37 -04:00
if ( ! GRDGAsyncCompute | | ! GSupportsEfficientAsyncCompute | | IsImmediateMode ( ) )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
Pipelines = ERHIPipeline : : Graphics ;
}
2021-04-06 11:45:09 -04:00
2022-05-04 12:41:19 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateUseExternalAccessMode ( Resource , ReadOnlyAccess , Pipelines ) ) ;
2022-04-25 13:00:12 -04:00
auto & AccessModeState = Resource - > AccessModeState ;
// We already validated that back-to-back calls to UseExternalAccessMode are valid only if the parameters match,
// so we can safely no-op this call.
if ( AccessModeState . Mode = = FRDGViewableResource : : EAccessMode : : External )
{
return ;
}
// We have to flush the queue when going from QueuedInternal -> External. A queued internal state
// implies that the resource was in an external access mode before, so it needs an 'end' pass to
// contain any passes which might have used the resource in its external state.
2022-05-02 18:31:37 -04:00
if ( AccessModeState . bQueued )
2022-04-25 13:00:12 -04:00
{
FlushAccessModeQueue ( ) ;
}
2022-05-02 18:31:37 -04:00
check ( ! AccessModeState . bQueued ) ;
2022-04-25 13:00:12 -04:00
AccessModeQueue . Emplace ( Resource ) ;
2022-05-02 18:31:37 -04:00
AccessModeState . bQueued = 1 ;
2022-04-25 13:00:12 -04:00
Resource - > SetExternalAccessMode ( ReadOnlyAccess , Pipelines ) ;
}
void FRDGBuilder : : UseInternalAccessMode ( FRDGViewableResource * Resource )
{
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateUseInternalAccessMode ( Resource ) ) ;
auto & AccessModeState = Resource - > AccessModeState ;
2022-05-02 18:31:37 -04:00
// Just no-op if the resource is already in (or queued for) the Internal state.
2022-04-25 13:00:12 -04:00
if ( AccessModeState . Mode = = FRDGViewableResource : : EAccessMode : : Internal )
{
return ;
}
// If the resource has a queued transition to the external access state, then we can safely back it out.
2022-05-02 18:31:37 -04:00
if ( AccessModeState . bQueued )
2022-04-25 13:00:12 -04:00
{
2022-05-02 18:31:37 -04:00
int32 Index = AccessModeQueue . IndexOfByKey ( Resource ) ;
check ( Index < AccessModeQueue . Num ( ) ) ;
AccessModeQueue . RemoveAtSwap ( Index , 1 , false ) ;
AccessModeState . bQueued = 0 ;
2022-04-25 13:00:12 -04:00
}
else
{
AccessModeQueue . Emplace ( Resource ) ;
2022-05-02 18:31:37 -04:00
AccessModeState . bQueued = 1 ;
2022-04-25 13:00:12 -04:00
}
AccessModeState . Mode = FRDGViewableResource : : EAccessMode : : Internal ;
}
void FRDGBuilder : : FlushAccessModeQueue ( )
{
2022-05-04 12:41:19 -04:00
if ( AccessModeQueue . IsEmpty ( ) | | bInFlushExternalAccess )
2022-04-25 13:00:12 -04:00
{
return ;
}
2022-05-04 12:41:19 -04:00
bInFlushExternalAccess = true ;
2022-04-25 13:00:12 -04:00
FAccessModePassParameters * ParametersByPipeline [ ] =
{
AllocParameters < FAccessModePassParameters > ( ) ,
AllocParameters < FAccessModePassParameters > ( )
} ;
2022-05-02 18:31:37 -04:00
const ERHIAccess AccessMaskByPipeline [ ] =
{
ERHIAccess : : ReadOnlyExclusiveMask ,
ERHIAccess : : ReadOnlyExclusiveComputeMask
} ;
2022-04-25 13:00:12 -04:00
ERHIPipeline ParameterPipelines = ERHIPipeline : : None ;
for ( FRDGViewableResource * Resource : AccessModeQueue )
{
const auto & AccessModeState = Resource - > AccessModeState ;
ParameterPipelines | = AccessModeState . Pipelines ;
2022-05-02 18:31:37 -04:00
if ( AccessModeState . Mode = = FRDGViewableResource : : EAccessMode : : External )
{
ExternalAccessResources . Emplace ( Resource ) ;
}
else
{
ExternalAccessResources . Remove ( Resource ) ;
}
2022-04-25 13:00:12 -04:00
for ( uint32 PipelineIndex = 0 ; PipelineIndex < GetRHIPipelineCount ( ) ; + + PipelineIndex )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
const ERHIPipeline Pipeline = static_cast < ERHIPipeline > ( 1 < < PipelineIndex ) ;
if ( EnumHasAnyFlags ( AccessModeState . Pipelines , Pipeline ) )
{
2022-05-02 18:31:37 -04:00
const ERHIAccess Access = AccessModeState . Access & AccessMaskByPipeline [ PipelineIndex ] ;
check ( Access ! = ERHIAccess : : None ) ;
2022-04-25 13:00:12 -04:00
switch ( Resource - > Type )
{
case ERDGViewableResourceType : : Texture :
2022-05-02 18:31:37 -04:00
ParametersByPipeline [ PipelineIndex ] - > Textures . Emplace ( GetAsTexture ( Resource ) , Access ) ;
2022-04-25 13:00:12 -04:00
break ;
case ERDGViewableResourceType : : Buffer :
2022-05-02 18:31:37 -04:00
ParametersByPipeline [ PipelineIndex ] - > Buffers . Emplace ( GetAsBuffer ( Resource ) , Access ) ;
2022-04-25 13:00:12 -04:00
break ;
}
}
2021-04-06 11:45:09 -04:00
}
}
2022-04-25 13:00:12 -04:00
if ( EnumHasAnyFlags ( ParameterPipelines , ERHIPipeline : : Graphics ) )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
FAccessModePassParameters * Parameters = ParametersByPipeline [ GetRHIPipelineIndex ( ERHIPipeline : : Graphics ) ] ;
AddPass (
RDG_EVENT_NAME ( " AccessModePass[Graphics] (Textures: %d, Buffers: %d) " , Parameters - > Textures . Num ( ) , Parameters - > Buffers . Num ( ) ) ,
Parameters ,
// Use all of the work flags so that any access is valid.
ERDGPassFlags : : Copy | ERDGPassFlags : : Compute | ERDGPassFlags : : Raster | ERDGPassFlags : : SkipRenderPass | ERDGPassFlags : : NeverCull ,
[ ] ( FRHICommandList & ) { } ) ;
2021-04-06 11:45:09 -04:00
}
2022-04-25 13:00:12 -04:00
if ( EnumHasAnyFlags ( ParameterPipelines , ERHIPipeline : : AsyncCompute ) )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
FAccessModePassParameters * Parameters = ParametersByPipeline [ GetRHIPipelineIndex ( ERHIPipeline : : AsyncCompute ) ] ;
AddPass (
RDG_EVENT_NAME ( " AccessModePass[AsyncCompute] (Textures: %d, Buffers: %d) " , Parameters - > Textures . Num ( ) , Parameters - > Buffers . Num ( ) ) ,
Parameters ,
ERDGPassFlags : : AsyncCompute | ERDGPassFlags : : NeverCull ,
[ ] ( FRHIComputeCommandList & ) { } ) ;
2021-04-06 11:45:09 -04:00
}
2022-04-25 13:00:12 -04:00
2022-05-02 18:31:37 -04:00
// This has to be done *after* adding the passes so they don't inherit the new access mode.
2022-04-25 13:00:12 -04:00
for ( FRDGViewableResource * Resource : AccessModeQueue )
{
2022-05-02 18:31:37 -04:00
Resource - > AccessModeState . bQueued = false ;
2022-04-25 13:00:12 -04:00
}
AccessModeQueue . Reset ( ) ;
2022-05-04 12:41:19 -04:00
bInFlushExternalAccess = false ;
2020-09-24 00:43:27 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
FRDGTextureRef FRDGBuilder : : RegisterExternalTexture (
const TRefCountPtr < IPooledRenderTarget > & ExternalPooledTexture ,
2022-01-26 15:04:14 -05:00
ERDGTextureFlags Flags )
2020-09-24 00:43:27 -04:00
{
# if RDG_ENABLE_DEBUG
checkf ( ExternalPooledTexture . IsValid ( ) , TEXT ( " Attempted to register NULL external texture. " ) ) ;
# endif
const TCHAR * Name = ExternalPooledTexture - > GetDesc ( ) . DebugName ;
if ( ! Name )
{
Name = TEXT ( " External " ) ;
}
2022-01-31 17:22:31 -05:00
return RegisterExternalTexture ( ExternalPooledTexture , Name , Flags ) ;
2020-03-25 13:21:18 -04:00
}
2022-04-22 17:11:57 -04:00
FRDGTexture * FRDGBuilder : : RegisterExternalTexture (
2020-07-06 18:58:26 -04:00
const TRefCountPtr < IPooledRenderTarget > & ExternalPooledTexture ,
const TCHAR * Name ,
2022-01-26 15:04:14 -05:00
ERDGTextureFlags Flags )
2020-07-06 18:58:26 -04:00
{
2022-01-31 17:22:31 -05:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateRegisterExternalTexture ( ExternalPooledTexture , Name , Flags ) ) ;
FRHITexture * ExternalTextureRHI = ExternalPooledTexture - > GetRHI ( ) ;
2020-09-24 00:43:27 -04:00
IF_RDG_ENABLE_DEBUG ( checkf ( ExternalTextureRHI , TEXT ( " Attempted to register texture %s, but its RHI texture is null. " ) , Name ) ) ;
2022-04-22 17:11:57 -04:00
if ( FRDGTexture * FoundTexture = FindExternalTexture ( ExternalTextureRHI ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
return FoundTexture ;
2020-07-06 18:58:26 -04:00
}
2022-01-31 17:22:31 -05:00
const FRDGTextureDesc Desc = Translate ( ExternalPooledTexture - > GetDesc ( ) ) ;
2022-04-25 13:00:12 -04:00
FRDGTexture * Texture = Textures . Allocate ( Allocator , Name , Desc , Flags ) ;
2022-03-25 11:19:10 -04:00
SetRHI ( Texture , ExternalPooledTexture . GetReference ( ) , GetProloguePassHandle ( ) ) ;
2020-09-24 00:43:27 -04:00
Texture - > bExternal = true ;
ExternalTextures . Add ( Texture - > GetRHIUnchecked ( ) , Texture ) ;
2020-11-17 17:04:48 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateRegisterExternalTexture ( Texture ) ) ;
2021-02-05 12:11:16 -04:00
IF_RDG_ENABLE_TRACE ( Trace . AddResource ( Texture ) ) ;
2020-09-24 00:43:27 -04:00
return Texture ;
}
2022-01-26 15:04:14 -05:00
FRDGBufferRef FRDGBuilder : : RegisterExternalBuffer ( const TRefCountPtr < FRDGPooledBuffer > & ExternalPooledBuffer , ERDGBufferFlags Flags )
2020-09-24 00:43:27 -04:00
{
# if RDG_ENABLE_DEBUG
checkf ( ExternalPooledBuffer . IsValid ( ) , TEXT ( " Attempted to register NULL external buffer. " ) ) ;
# endif
const TCHAR * Name = ExternalPooledBuffer - > Name ;
if ( ! Name )
{
Name = TEXT ( " External " ) ;
}
2022-01-26 15:04:14 -05:00
return RegisterExternalBuffer ( ExternalPooledBuffer , Name , Flags ) ;
2020-07-06 18:58:26 -04:00
}
FRDGBufferRef FRDGBuilder : : RegisterExternalBuffer (
2020-09-24 00:43:27 -04:00
const TRefCountPtr < FRDGPooledBuffer > & ExternalPooledBuffer ,
2020-07-06 18:58:26 -04:00
const TCHAR * Name ,
2022-01-26 15:04:14 -05:00
ERDGBufferFlags Flags )
2020-07-06 18:58:26 -04:00
{
2020-11-17 17:04:48 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateRegisterExternalBuffer ( ExternalPooledBuffer , Name , Flags ) ) ;
2020-07-06 18:58:26 -04:00
2022-04-22 17:11:57 -04:00
if ( FRDGBuffer * FoundBuffer = FindExternalBuffer ( ExternalPooledBuffer ) )
2020-07-06 18:58:26 -04:00
{
2022-04-22 17:11:57 -04:00
return FoundBuffer ;
2020-07-06 18:58:26 -04:00
}
2022-04-25 13:00:12 -04:00
FRDGBuffer * Buffer = Buffers . Allocate ( Allocator , Name , ExternalPooledBuffer - > Desc , Flags ) ;
2022-03-25 11:19:10 -04:00
SetRHI ( Buffer , ExternalPooledBuffer , GetProloguePassHandle ( ) ) ;
2020-09-24 00:43:27 -04:00
Buffer - > bExternal = true ;
2022-04-22 17:11:57 -04:00
ExternalBuffers . Add ( Buffer - > GetRHIUnchecked ( ) , Buffer ) ;
2020-09-24 00:43:27 -04:00
2020-11-17 17:04:48 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateRegisterExternalBuffer ( Buffer ) ) ;
2021-02-05 12:11:16 -04:00
IF_RDG_ENABLE_TRACE ( Trace . AddResource ( Buffer ) ) ;
2020-09-24 00:43:27 -04:00
return Buffer ;
2020-07-06 18:58:26 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2020-09-24 00:43:27 -04:00
void FRDGBuilder : : AddPassDependency ( FRDGPassHandle ProducerHandle , FRDGPassHandle ConsumerHandle )
2020-07-06 18:58:26 -04:00
{
FRDGPass * Consumer = Passes [ ConsumerHandle ] ;
2020-09-24 00:43:27 -04:00
auto & Producers = Consumer - > Producers ;
if ( Producers . Find ( ProducerHandle ) = = INDEX_NONE )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
Producers . Add ( ProducerHandle ) ;
2021-05-25 17:11:34 -04:00
}
2020-09-24 00:43:27 -04:00
# if STATS
2021-07-13 12:38:37 -04:00
GRDGStatPassDependencyCount + + ;
2020-09-24 00:43:27 -04:00
# endif
2021-05-25 17:11:34 -04:00
}
2020-07-06 18:58:26 -04:00
2022-01-31 15:55:31 -05:00
void FRDGBuilder : : Compile ( )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
SCOPE_CYCLE_COUNTER ( STAT_RDG_CompileTime ) ;
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL ( RDG_Compile , GRDGVerboseCSVStats ! = 0 ) ;
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( Compile , FColor : : Emerald ) ;
2020-07-06 18:58:26 -04:00
2022-03-25 11:19:10 -04:00
const FRDGPassHandle ProloguePassHandle = GetProloguePassHandle ( ) ;
2020-09-24 00:43:27 -04:00
const FRDGPassHandle EpiloguePassHandle = GetEpiloguePassHandle ( ) ;
2020-07-06 18:58:26 -04:00
2022-01-31 15:55:31 -05:00
const uint32 CompilePassCount = Passes . Num ( ) ;
2020-07-06 18:58:26 -04:00
2022-01-31 15:55:31 -05:00
const bool bCullPasses = GRDGCullPasses > 0 ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
TArray < FRDGPassHandle , FRDGArrayAllocator > PassStack ;
if ( bCullPasses )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
PassStack . Reserve ( CompilePassCount ) ;
}
TransitionCreateQueue . Reserve ( CompilePassCount ) ;
2020-07-06 18:58:26 -04:00
2022-01-31 15:55:31 -05:00
FRDGPassBitArray PassesOnAsyncCompute ( false , CompilePassCount ) ;
2020-09-24 00:43:27 -04:00
// Build producer / consumer dependencies across the graph and construct packed bit-arrays of metadata
// for better cache coherency when searching for passes meeting specific criteria. Search roots are also
// identified for culling. Passes with untracked RHI output (e.g. SHADER_PARAMETER_{BUFFER, TEXTURE}_UAV)
// cannot be culled, nor can any pass which writes to an external resource. Resource extractions extend the
// lifetime to the epilogue pass which is always a root of the graph. The prologue and epilogue are helper
// passes and therefore never culled.
2021-05-19 17:54:58 -04:00
if ( bCullPasses | | AsyncComputePassCount > 0 )
2020-07-06 18:58:26 -04:00
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( PassDependencies , FColor : : Emerald ) ;
2020-07-06 18:58:26 -04:00
2020-11-30 13:27:08 -04:00
const auto AddCullingDependency = [ & ] ( FRDGProducerStatesByPipeline & LastProducers , const FRDGProducerState & NextState , ERHIPipeline NextPipeline )
2020-07-06 18:58:26 -04:00
{
2020-11-30 13:27:08 -04:00
for ( ERHIPipeline LastPipeline : GetRHIPipelines ( ) )
{
FRDGProducerState & LastProducer = LastProducers [ LastPipeline ] ;
if ( LastProducer . Access = = ERHIAccess : : Unknown )
2020-09-24 00:43:27 -04:00
{
2020-11-30 13:27:08 -04:00
continue ;
2020-09-24 00:43:27 -04:00
}
2020-11-30 13:27:08 -04:00
if ( FRDGProducerState : : IsDependencyRequired ( LastProducer , LastPipeline , NextState , NextPipeline ) )
2020-09-24 00:43:27 -04:00
{
2020-11-30 13:27:08 -04:00
AddPassDependency ( LastProducer . PassHandle , NextState . PassHandle ) ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
}
2020-11-30 13:27:08 -04:00
if ( IsWritableAccess ( NextState . Access ) )
{
LastProducers [ NextPipeline ] = NextState ;
}
2020-09-24 00:43:27 -04:00
} ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGPass * Pass = Passes [ PassHandle ] ;
2021-05-19 17:54:58 -04:00
const ERHIPipeline PassPipeline = Pass - > Pipeline ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
bool bUntrackedOutputs = Pass - > bHasExternalOutputs ;
2020-09-30 14:23:56 -04:00
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > TextureStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGTextureRef Texture = PassState . Texture ;
2020-09-24 00:43:27 -04:00
auto & LastProducers = Texture - > LastProducers ;
for ( uint32 Index = 0 , Count = LastProducers . Num ( ) ; Index < Count ; + + Index )
{
2021-05-05 11:58:15 -04:00
const auto & SubresourceState = PassState . State [ Index ] ;
if ( SubresourceState . Access = = ERHIAccess : : Unknown )
{
continue ;
}
2020-11-30 13:27:08 -04:00
FRDGProducerState ProducerState ;
ProducerState . Access = SubresourceState . Access ;
ProducerState . PassHandle = PassHandle ;
ProducerState . NoUAVBarrierHandle = SubresourceState . NoUAVBarrierFilter . GetUniqueHandle ( ) ;
AddCullingDependency ( LastProducers [ Index ] , ProducerState , PassPipeline ) ;
2020-09-24 00:43:27 -04:00
}
2020-09-30 14:23:56 -04:00
bUntrackedOutputs | = Texture - > bExternal ;
2020-09-24 00:43:27 -04:00
}
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > BufferStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGBufferRef Buffer = PassState . Buffer ;
const auto & SubresourceState = PassState . State ;
2020-11-30 13:27:08 -04:00
FRDGProducerState ProducerState ;
ProducerState . Access = SubresourceState . Access ;
ProducerState . PassHandle = PassHandle ;
ProducerState . NoUAVBarrierHandle = SubresourceState . NoUAVBarrierFilter . GetUniqueHandle ( ) ;
AddCullingDependency ( Buffer - > LastProducer , ProducerState , PassPipeline ) ;
2020-09-30 14:23:56 -04:00
bUntrackedOutputs | = Buffer - > bExternal ;
2020-09-24 00:43:27 -04:00
}
2021-05-19 17:54:58 -04:00
PassesOnAsyncCompute [ PassHandle ] = EnumHasAnyFlags ( Pass - > Flags , ERDGPassFlags : : AsyncCompute ) ;
Pass - > bCulled = bCullPasses ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
if ( bCullPasses & & ( bUntrackedOutputs | | EnumHasAnyFlags ( Pass - > Flags , ERDGPassFlags : : NeverCull ) ) )
{
PassStack . Emplace ( PassHandle ) ;
}
2020-09-24 00:43:27 -04:00
}
2022-01-31 15:55:31 -05:00
for ( const FExtractedTexture & ExtractedTexture : ExtractedTextures )
2020-09-24 00:43:27 -04:00
{
2022-01-31 15:55:31 -05:00
FRDGTextureRef Texture = ExtractedTexture . Texture ;
for ( auto & LastProducer : Texture - > LastProducers )
2020-09-24 00:43:27 -04:00
{
2020-11-30 13:27:08 -04:00
FRDGProducerState StateFinal ;
2022-03-25 11:19:10 -04:00
StateFinal . Access = Texture - > EpilogueAccess ;
2020-11-30 13:27:08 -04:00
StateFinal . PassHandle = EpiloguePassHandle ;
2022-01-31 15:55:31 -05:00
AddCullingDependency ( LastProducer , StateFinal , ERHIPipeline : : Graphics ) ;
2020-09-24 00:43:27 -04:00
}
}
2022-01-31 15:55:31 -05:00
for ( const FExtractedBuffer & ExtractedBuffer : ExtractedBuffers )
{
FRDGBufferRef Buffer = ExtractedBuffer . Buffer ;
FRDGProducerState StateFinal ;
2022-03-25 11:19:10 -04:00
StateFinal . Access = Buffer - > EpilogueAccess ;
2022-01-31 15:55:31 -05:00
StateFinal . PassHandle = EpiloguePassHandle ;
AddCullingDependency ( Buffer - > LastProducer , StateFinal , ERHIPipeline : : Graphics ) ;
}
2020-09-24 00:43:27 -04:00
}
// All dependencies in the raw graph have been specified; if enabled, all passes are marked as culled and a
// depth first search is employed to find reachable regions of the graph. Roots of the search are those passes
// with outputs leaving the graph or those marked to never cull.
2021-05-19 17:54:58 -04:00
if ( bCullPasses )
2020-09-24 00:43:27 -04:00
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( PassCulling , FColor : : Emerald ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
PassStack . Emplace ( EpiloguePassHandle ) ;
2020-09-24 00:43:27 -04:00
2021-05-25 20:46:17 -04:00
// Mark the epilogue pass as culled so that it is traversed.
EpiloguePass - > bCulled = 1 ;
2021-05-19 17:54:58 -04:00
// Manually mark the prologue passes as not culled.
2022-01-31 15:55:31 -05:00
ProloguePass - > bCulled = 0 ;
2020-07-06 18:58:26 -04:00
while ( PassStack . Num ( ) )
{
2021-05-19 17:54:58 -04:00
FRDGPass * Pass = Passes [ PassStack . Pop ( ) ] ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
if ( Pass - > bCulled )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
Pass - > bCulled = 0 ;
PassStack . Append ( Pass - > Producers ) ;
2020-09-24 00:43:27 -04:00
}
}
}
// Walk the culled graph and compile barriers for each subresource. Certain transitions are redundant; read-to-read, for example.
// We can avoid them by traversing and merging compatible states together. The merging states removes a transition, but the merging
// heuristic is conservative and choosing not to merge doesn't necessarily mean a transition is performed. They are two distinct steps.
// Merged states track the first and last pass interval. Pass references are also accumulated onto each resource. This must happen
// after culling since culled passes can't contribute references.
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( CompileBarriers , FColor : : Emerald ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( Pass - > bCulled | | Pass - > bEmptyParameters )
2020-09-24 00:43:27 -04:00
{
continue ;
}
2020-11-11 19:22:36 -04:00
const bool bAsyncComputePass = PassesOnAsyncCompute [ PassHandle ] ;
2021-05-19 17:54:58 -04:00
const ERHIPipeline PassPipeline = Pass - > Pipeline ;
2020-11-11 19:22:36 -04:00
2022-03-25 11:19:10 -04:00
const auto MergeSubresourceStates = [ & ] ( ERDGViewableResourceType ResourceType , FRDGSubresourceState * & PassMergeState , FRDGSubresourceState * & ResourceMergeState , const FRDGSubresourceState & PassState )
2020-09-24 00:43:27 -04:00
{
2022-01-31 15:55:31 -05:00
if ( ! ResourceMergeState | | ! FRDGSubresourceState : : IsMergeAllowed ( ResourceType , * ResourceMergeState , PassState ) )
2020-09-24 00:43:27 -04:00
{
// Cross-pipeline, non-mergable state changes require a new pass dependency for fencing purposes.
2020-11-11 19:22:36 -04:00
if ( ResourceMergeState )
2020-09-24 00:43:27 -04:00
{
2020-11-11 19:22:36 -04:00
for ( ERHIPipeline Pipeline : GetRHIPipelines ( ) )
{
if ( Pipeline ! = PassPipeline & & ResourceMergeState - > LastPass [ Pipeline ] . IsValid ( ) )
{
// Add a dependency from the other pipe to this pass to join back.
AddPassDependency ( ResourceMergeState - > LastPass [ Pipeline ] , PassHandle ) ;
}
}
2020-09-24 00:43:27 -04:00
}
// Allocate a new pending merge state and assign it to the pass state.
ResourceMergeState = AllocSubresource ( PassState ) ;
}
else
{
// Merge the pass state into the merged state.
ResourceMergeState - > Access | = PassState . Access ;
2020-11-11 19:22:36 -04:00
FRDGPassHandle & FirstPassHandle = ResourceMergeState - > FirstPass [ PassPipeline ] ;
if ( FirstPassHandle . IsNull ( ) )
{
FirstPassHandle = PassHandle ;
}
ResourceMergeState - > LastPass [ PassPipeline ] = PassHandle ;
2020-09-24 00:43:27 -04:00
}
PassMergeState = ResourceMergeState ;
} ;
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > TextureStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGTextureRef Texture = PassState . Texture ;
2020-09-24 00:43:27 -04:00
Texture - > ReferenceCount + = PassState . ReferenceCount ;
Texture - > bUsedByAsyncComputePass | = bAsyncComputePass ;
2021-05-25 20:46:17 -04:00
Texture - > bCulled = false ;
2020-09-24 00:43:27 -04:00
2022-04-22 17:11:57 -04:00
if ( Texture - > FirstBarrier = = FRDGTexture : : EFirstBarrier : : ImmediateRequested )
2021-07-14 11:51:24 -04:00
{
2022-04-22 17:11:57 -04:00
Texture - > FirstBarrier = FRDGTexture : : EFirstBarrier : : ImmediateConfirmed ;
2021-07-14 11:51:24 -04:00
Texture - > FirstPass = PassHandle ;
GetWholeResource ( Texture - > GetState ( ) ) . SetPass ( ERHIPipeline : : Graphics , PassHandle ) ;
}
2021-05-05 11:58:15 -04:00
# if STATS
GRDGStatTextureReferenceCount + = PassState . ReferenceCount ;
# endif
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
for ( int32 Index = 0 ; Index < PassState . State . Num ( ) ; + + Index )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
if ( PassState . State [ Index ] . Access = = ERHIAccess : : Unknown )
{
continue ;
}
2022-03-25 11:19:10 -04:00
MergeSubresourceStates ( ERDGViewableResourceType : : Texture , PassState . MergeState [ Index ] , Texture - > MergeState [ Index ] , PassState . State [ Index ] ) ;
2020-09-24 00:43:27 -04:00
}
}
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > BufferStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGBufferRef Buffer = PassState . Buffer ;
2020-09-24 00:43:27 -04:00
Buffer - > ReferenceCount + = PassState . ReferenceCount ;
Buffer - > bUsedByAsyncComputePass | = bAsyncComputePass ;
2021-05-25 20:46:17 -04:00
Buffer - > bCulled = false ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
# if STATS
GRDGStatBufferReferenceCount + = PassState . ReferenceCount ;
# endif
2022-03-25 11:19:10 -04:00
MergeSubresourceStates ( ERDGViewableResourceType : : Buffer , PassState . MergeState , Buffer - > MergeState , PassState . State ) ;
2020-07-06 18:58:26 -04:00
}
}
}
2021-03-25 20:08:40 -04:00
// Traverses passes on the graphics pipe and merges raster passes with the same render targets into a single RHI render pass.
2021-05-19 17:54:58 -04:00
if ( IsRenderPassMergeEnabled ( ) & & RasterPassCount > 0 )
2021-03-25 20:08:40 -04:00
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( MergeRenderPasses , FColor : : Emerald ) ;
2021-03-25 20:08:40 -04:00
2021-05-19 17:54:58 -04:00
TArray < FRDGPassHandle , TInlineAllocator < 32 , FRDGArrayAllocator > > PassesToMerge ;
2021-03-25 20:08:40 -04:00
FRDGPass * PrevPass = nullptr ;
const FRenderTargetBindingSlots * PrevRenderTargets = nullptr ;
const auto CommitMerge = [ & ]
{
if ( PassesToMerge . Num ( ) )
{
2021-05-05 11:58:15 -04:00
const auto SetEpilogueBarrierPass = [ & ] ( FRDGPass * Pass , FRDGPassHandle EpilogueBarrierPassHandle )
{
Pass - > EpilogueBarrierPass = EpilogueBarrierPassHandle ;
Pass - > ResourcesToEnd . Reset ( ) ;
Passes [ EpilogueBarrierPassHandle ] - > ResourcesToEnd . Add ( Pass ) ;
} ;
const auto SetPrologueBarrierPass = [ & ] ( FRDGPass * Pass , FRDGPassHandle PrologueBarrierPassHandle )
{
Pass - > PrologueBarrierPass = PrologueBarrierPassHandle ;
Pass - > ResourcesToBegin . Reset ( ) ;
Passes [ PrologueBarrierPassHandle ] - > ResourcesToBegin . Add ( Pass ) ;
} ;
2021-03-25 20:08:40 -04:00
const FRDGPassHandle FirstPassHandle = PassesToMerge [ 0 ] ;
const FRDGPassHandle LastPassHandle = PassesToMerge . Last ( ) ;
2021-05-05 11:58:15 -04:00
Passes [ FirstPassHandle ] - > ResourcesToBegin . Reserve ( PassesToMerge . Num ( ) ) ;
Passes [ LastPassHandle ] - > ResourcesToEnd . Reserve ( PassesToMerge . Num ( ) ) ;
2021-03-25 20:08:40 -04:00
// Given an interval of passes to merge into a single render pass: [B, X, X, X, X, E]
//
// The begin pass (B) and end (E) passes will call {Begin, End}RenderPass, respectively. Also,
// begin will handle all prologue barriers for the entire merged interval, and end will handle all
// epilogue barriers. This avoids transitioning of resources within the render pass and batches the
// transitions more efficiently. This assumes we have filtered out dependencies between passes from
// the merge set, which is done during traversal.
// (B) First pass in the merge sequence.
{
FRDGPass * Pass = Passes [ FirstPassHandle ] ;
Pass - > bSkipRenderPassEnd = 1 ;
2021-05-05 11:58:15 -04:00
SetEpilogueBarrierPass ( Pass , LastPassHandle ) ;
2021-03-25 20:08:40 -04:00
}
// (X) Intermediate passes.
for ( int32 PassIndex = 1 , PassCount = PassesToMerge . Num ( ) - 1 ; PassIndex < PassCount ; + + PassIndex )
{
const FRDGPassHandle PassHandle = PassesToMerge [ PassIndex ] ;
FRDGPass * Pass = Passes [ PassHandle ] ;
Pass - > bSkipRenderPassBegin = 1 ;
Pass - > bSkipRenderPassEnd = 1 ;
2021-05-05 11:58:15 -04:00
SetPrologueBarrierPass ( Pass , FirstPassHandle ) ;
SetEpilogueBarrierPass ( Pass , LastPassHandle ) ;
2021-03-25 20:08:40 -04:00
}
// (E) Last pass in the merge sequence.
{
FRDGPass * Pass = Passes [ LastPassHandle ] ;
Pass - > bSkipRenderPassBegin = 1 ;
2021-05-05 11:58:15 -04:00
SetPrologueBarrierPass ( Pass , FirstPassHandle ) ;
2021-03-25 20:08:40 -04:00
}
# if STATS
GRDGStatRenderPassMergeCount + = PassesToMerge . Num ( ) ;
# endif
}
PassesToMerge . Reset ( ) ;
PrevPass = nullptr ;
PrevRenderTargets = nullptr ;
} ;
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2021-03-25 20:08:40 -04:00
{
2021-05-19 17:54:58 -04:00
FRDGPass * NextPass = Passes [ PassHandle ] ;
if ( NextPass - > bCulled | | NextPass - > bEmptyParameters )
2021-03-25 20:08:40 -04:00
{
continue ;
}
2021-05-19 17:54:58 -04:00
if ( EnumHasAnyFlags ( NextPass - > Flags , ERDGPassFlags : : Raster ) )
2021-03-25 20:08:40 -04:00
{
2021-04-12 15:36:14 -04:00
// A pass where the user controls the render pass or it is forced to skip pass merging can't merge with other passes
2021-05-19 17:54:58 -04:00
if ( EnumHasAnyFlags ( NextPass - > Flags , ERDGPassFlags : : SkipRenderPass | ERDGPassFlags : : NeverMerge ) )
2021-03-25 20:08:40 -04:00
{
CommitMerge ( ) ;
continue ;
}
// A pass which writes to resources outside of the render pass introduces new dependencies which break merging.
if ( ! NextPass - > bRenderPassOnlyWrites )
{
CommitMerge ( ) ;
continue ;
}
const FRenderTargetBindingSlots & RenderTargets = NextPass - > GetParameters ( ) . GetRenderTargets ( ) ;
if ( PrevPass )
{
check ( PrevRenderTargets ) ;
if ( PrevRenderTargets - > CanMergeBefore ( RenderTargets )
# if WITH_MGPU
& & PrevPass - > GPUMask = = NextPass - > GPUMask
# endif
)
{
if ( ! PassesToMerge . Num ( ) )
{
PassesToMerge . Add ( PrevPass - > GetHandle ( ) ) ;
}
PassesToMerge . Add ( PassHandle ) ;
}
else
{
CommitMerge ( ) ;
}
}
PrevPass = NextPass ;
PrevRenderTargets = & RenderTargets ;
}
2021-05-19 17:54:58 -04:00
else if ( ! EnumHasAnyFlags ( NextPass - > Flags , ERDGPassFlags : : AsyncCompute ) )
2021-03-25 20:08:40 -04:00
{
// A non-raster pass on the graphics pipe will invalidate the render target merge.
CommitMerge ( ) ;
}
}
CommitMerge ( ) ;
}
2020-09-24 00:43:27 -04:00
if ( AsyncComputePassCount > 0 )
2020-07-06 18:58:26 -04:00
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( AsyncComputeFences , FColor : : Emerald ) ;
2020-09-24 00:43:27 -04:00
// Traverse the active passes in execution order to find latest cross-pipeline producer and the earliest
// cross-pipeline consumer for each pass. This helps narrow the search space later when building async
// compute overlap regions.
2021-05-19 17:54:58 -04:00
const auto IsCrossPipeline = [ & ] ( FRDGPassHandle A , FRDGPassHandle B )
{
return PassesOnAsyncCompute [ A ] ! = PassesOnAsyncCompute [ B ] ;
} ;
2020-09-24 00:43:27 -04:00
FRDGPassBitArray PassesWithCrossPipelineProducer ( false , Passes . Num ( ) ) ;
FRDGPassBitArray PassesWithCrossPipelineConsumer ( false , Passes . Num ( ) ) ;
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( Pass - > bCulled | | Pass - > bEmptyParameters )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
continue ;
}
for ( FRDGPassHandle ProducerHandle : Pass - > GetProducers ( ) )
{
const FRDGPassHandle ConsumerHandle = PassHandle ;
if ( ! IsCrossPipeline ( ProducerHandle , ConsumerHandle ) )
{
continue ;
}
2020-07-06 18:58:26 -04:00
FRDGPass * Consumer = Pass ;
FRDGPass * Producer = Passes [ ProducerHandle ] ;
// Finds the earliest consumer on the other pipeline for the producer.
2021-05-19 17:54:58 -04:00
if ( Producer - > CrossPipelineConsumer . IsNull ( ) | | ConsumerHandle < Producer - > CrossPipelineConsumer )
2020-07-06 18:58:26 -04:00
{
Producer - > CrossPipelineConsumer = PassHandle ;
2020-09-24 00:43:27 -04:00
PassesWithCrossPipelineConsumer [ ProducerHandle ] = true ;
2020-07-06 18:58:26 -04:00
}
// Finds the latest producer on the other pipeline for the consumer.
2021-05-19 17:54:58 -04:00
if ( Consumer - > CrossPipelineProducer . IsNull ( ) | | ProducerHandle > Consumer - > CrossPipelineProducer )
2020-07-06 18:58:26 -04:00
{
Consumer - > CrossPipelineProducer = ProducerHandle ;
2020-09-24 00:43:27 -04:00
PassesWithCrossPipelineProducer [ ConsumerHandle ] = true ;
2020-07-06 18:58:26 -04:00
}
}
}
2020-09-24 00:43:27 -04:00
// Establishes fork / join overlap regions for async compute. This is used for fencing as well as resource
// allocation / deallocation. Async compute passes can't allocate / release their resource references until
// the fork / join is complete, since the two pipes run in parallel. Therefore, all resource lifetimes on
// async compute are extended to cover the full async region.
const auto IsCrossPipelineProducer = [ & ] ( FRDGPassHandle A )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
return PassesWithCrossPipelineConsumer [ A ] ;
} ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
const auto IsCrossPipelineConsumer = [ & ] ( FRDGPassHandle A )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
return PassesWithCrossPipelineProducer [ A ] ;
} ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
const auto FindCrossPipelineProducer = [ & ] ( FRDGPassHandle PassHandle )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGPassHandle LatestProducerHandle = ProloguePassHandle ;
FRDGPassHandle ConsumerHandle = PassHandle ;
// We want to find the latest producer on the other pipeline in order to establish a fork point.
// Since we could be consuming N resources with N producer passes, we only care about the last one.
2021-05-19 17:54:58 -04:00
while ( ConsumerHandle ! = ProloguePassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
if ( IsCrossPipelineConsumer ( ConsumerHandle ) & & ! IsCrossPipeline ( ConsumerHandle , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
const FRDGPass * Consumer = Passes [ ConsumerHandle ] ;
2021-05-19 17:54:58 -04:00
if ( Consumer - > CrossPipelineProducer > LatestProducerHandle & & ! Consumer - > bCulled )
2020-09-24 00:43:27 -04:00
{
LatestProducerHandle = Consumer - > CrossPipelineProducer ;
}
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
- - ConsumerHandle ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
return LatestProducerHandle ;
} ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
const auto FindCrossPipelineConsumer = [ & ] ( FRDGPassHandle PassHandle )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGPassHandle EarliestConsumerHandle = EpiloguePassHandle ;
FRDGPassHandle ProducerHandle = PassHandle ;
// We want to find the earliest consumer on the other pipeline, as this establishes a join point
// between the pipes. Since we could be producing for N consumers on the other pipeline, we only
// care about the first one to execute.
2021-05-19 17:54:58 -04:00
while ( ProducerHandle ! = EpiloguePassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
if ( IsCrossPipelineProducer ( ProducerHandle ) & & ! IsCrossPipeline ( ProducerHandle , PassHandle ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
const FRDGPass * Producer = Passes [ ProducerHandle ] ;
2021-05-19 17:54:58 -04:00
if ( Producer - > CrossPipelineConsumer < EarliestConsumerHandle & & ! Producer - > bCulled )
2020-09-24 00:43:27 -04:00
{
EarliestConsumerHandle = Producer - > CrossPipelineConsumer ;
}
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
+ + ProducerHandle ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
return EarliestConsumerHandle ;
} ;
2020-07-06 18:58:26 -04:00
const auto InsertGraphicsToAsyncComputeFork = [ & ] ( FRDGPass * GraphicsPass , FRDGPass * AsyncComputePass )
{
2021-05-19 17:54:58 -04:00
FRDGBarrierBatchBegin & EpilogueBarriersToBeginForAsyncCompute = GraphicsPass - > GetEpilogueBarriersToBeginForAsyncCompute ( Allocator , TransitionCreateQueue ) ;
2020-09-24 00:43:27 -04:00
2020-07-06 18:58:26 -04:00
GraphicsPass - > bGraphicsFork = 1 ;
2020-09-24 00:43:27 -04:00
EpilogueBarriersToBeginForAsyncCompute . SetUseCrossPipelineFence ( ) ;
2020-07-06 18:58:26 -04:00
AsyncComputePass - > bAsyncComputeBegin = 1 ;
2020-09-24 00:43:27 -04:00
AsyncComputePass - > GetPrologueBarriersToEnd ( Allocator ) . AddDependency ( & EpilogueBarriersToBeginForAsyncCompute ) ;
2020-07-06 18:58:26 -04:00
} ;
2021-05-19 17:54:58 -04:00
const auto InsertAsyncComputeToGraphicsJoin = [ & ] ( FRDGPass * AsyncComputePass , FRDGPass * GraphicsPass )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
FRDGBarrierBatchBegin & EpilogueBarriersToBeginForGraphics = AsyncComputePass - > GetEpilogueBarriersToBeginForGraphics ( Allocator , TransitionCreateQueue ) ;
2020-09-24 00:43:27 -04:00
2020-07-06 18:58:26 -04:00
AsyncComputePass - > bAsyncComputeEnd = 1 ;
2020-09-24 00:43:27 -04:00
EpilogueBarriersToBeginForGraphics . SetUseCrossPipelineFence ( ) ;
2020-07-06 18:58:26 -04:00
GraphicsPass - > bGraphicsJoin = 1 ;
2020-09-24 00:43:27 -04:00
GraphicsPass - > GetPrologueBarriersToEnd ( Allocator ) . AddDependency ( & EpilogueBarriersToBeginForGraphics ) ;
2020-07-06 18:58:26 -04:00
} ;
2022-01-20 16:30:26 -05:00
const auto AddResourcesToBegin = [ this ] ( FRDGPass * PassToBegin , FRDGPass * PassWithResources )
{
Passes [ PassToBegin - > PrologueBarrierPass ] - > ResourcesToBegin . Add ( PassWithResources ) ;
} ;
const auto AddResourcesToEnd = [ this ] ( FRDGPass * PassToEnd , FRDGPass * PassWithResources )
{
Passes [ PassToEnd - > EpilogueBarrierPass ] - > ResourcesToEnd . Add ( PassWithResources ) ;
} ;
2021-05-19 17:54:58 -04:00
FRDGPassHandle CurrentGraphicsForkPassHandle ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
if ( ! PassesOnAsyncCompute [ PassHandle ] )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
continue ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
FRDGPass * AsyncComputePass = Passes [ PassHandle ] ;
2021-05-19 17:54:58 -04:00
if ( AsyncComputePass - > bCulled )
{
continue ;
}
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
const FRDGPassHandle GraphicsForkPassHandle = FindCrossPipelineProducer ( PassHandle ) ;
2020-09-24 00:43:27 -04:00
FRDGPass * GraphicsForkPass = Passes [ GraphicsForkPassHandle ] ;
2021-05-19 17:54:58 -04:00
AsyncComputePass - > GraphicsForkPass = GraphicsForkPassHandle ;
2022-01-20 16:30:26 -05:00
AddResourcesToBegin ( GraphicsForkPass , AsyncComputePass ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
if ( CurrentGraphicsForkPassHandle ! = GraphicsForkPassHandle )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
CurrentGraphicsForkPassHandle = GraphicsForkPassHandle ;
2020-09-24 00:43:27 -04:00
InsertGraphicsToAsyncComputeFork ( GraphicsForkPass , AsyncComputePass ) ;
}
2020-07-06 18:58:26 -04:00
}
2021-05-19 17:54:58 -04:00
FRDGPassHandle CurrentGraphicsJoinPassHandle ;
for ( FRDGPassHandle PassHandle = EpiloguePassHandle - 1 ; PassHandle > ProloguePassHandle ; - - PassHandle )
{
if ( ! PassesOnAsyncCompute [ PassHandle ] )
{
continue ;
}
FRDGPass * AsyncComputePass = Passes [ PassHandle ] ;
if ( AsyncComputePass - > bCulled )
{
continue ;
}
const FRDGPassHandle GraphicsJoinPassHandle = FindCrossPipelineConsumer ( PassHandle ) ;
FRDGPass * GraphicsJoinPass = Passes [ GraphicsJoinPassHandle ] ;
AsyncComputePass - > GraphicsJoinPass = GraphicsJoinPassHandle ;
GraphicsJoinPass - > ResourcesToEnd . Add ( AsyncComputePass ) ;
if ( CurrentGraphicsJoinPassHandle ! = GraphicsJoinPassHandle )
{
CurrentGraphicsJoinPassHandle = GraphicsJoinPassHandle ;
InsertAsyncComputeToGraphicsJoin ( AsyncComputePass , GraphicsJoinPass ) ;
}
}
2020-07-06 18:58:26 -04:00
}
}
2019-06-11 18:27:07 -04:00
2018-10-22 14:28:32 -04:00
void FRDGBuilder : : Execute ( )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
CSV_SCOPED_TIMING_STAT_EXCLUSIVE ( RDG ) ;
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::Execute " , FColor : : Magenta ) ;
2018-11-21 20:33:41 -05:00
2022-01-03 18:28:16 -05:00
GRDGTransientResourceAllocator . ReleasePendingDeallocations ( ) ;
2022-05-02 18:31:37 -04:00
{
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::FlushAccessModeQueue " , FColor : : Magenta ) ;
for ( FRDGViewableResource * Resource : ExternalAccessResources )
{
UseInternalAccessMode ( Resource ) ;
}
FlushAccessModeQueue ( ) ;
}
2022-01-03 18:28:16 -05:00
2020-09-24 00:43:27 -04:00
// Create the epilogue pass at the end of the graph just prior to compilation.
2022-05-04 12:41:19 -04:00
SetupEmptyPass ( EpiloguePass = Passes . Allocate < FRDGSentinelPass > ( Allocator , RDG_EVENT_NAME ( " Graph Epilogue " ) ) ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2022-03-25 11:19:10 -04:00
const FRDGPassHandle ProloguePassHandle = GetProloguePassHandle ( ) ;
2020-09-24 00:43:27 -04:00
const FRDGPassHandle EpiloguePassHandle = GetEpiloguePassHandle ( ) ;
2019-06-11 18:27:07 -04:00
2021-07-22 12:43:00 -04:00
FGraphEventArray AsyncCompileEvents ;
2022-01-31 15:55:31 -05:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExecuteBegin ( ) ) ;
2021-05-19 17:54:58 -04:00
IF_RDG_ENABLE_DEBUG ( GRDGAllowRHIAccess = true ) ;
2021-03-17 12:44:59 -04:00
if ( ! IsImmediateMode ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2021-07-13 12:38:37 -04:00
BeginFlushResourcesRHI ( ) ;
2022-01-31 15:55:31 -05:00
Compile ( ) ;
2020-09-24 00:43:27 -04:00
2021-07-22 12:43:00 -04:00
IF_RDG_GPU_SCOPES ( GPUScopeStacks . ReserveOps ( Passes . Num ( ) ) ) ;
IF_RDG_CPU_SCOPES ( CPUScopeStacks . ReserveOps ( ) ) ;
2021-07-13 12:38:37 -04:00
2021-07-22 12:43:00 -04:00
if ( bParallelExecuteEnabled )
{
2021-10-12 21:21:22 -04:00
# if RHI_WANT_BREADCRUMB_EVENTS
RHICmdList . ExportBreadcrumbState ( * BreadcrumbState ) ;
# endif
2021-07-22 12:43:00 -04:00
// Parallel execute setup can be done off the render thread and synced prior to dispatch.
AsyncCompileEvents . Emplace ( FFunctionGraphTask : : CreateAndDispatchWhenReady (
[ this ] ( ENamedThreads : : Type , const FGraphEventRef & )
{
SetupParallelExecute ( ) ;
} , TStatId ( ) , nullptr , ENamedThreads : : AnyHiPriThreadHiPriTask ) ) ;
}
2021-05-25 20:46:17 -04:00
2022-05-04 12:41:19 -04:00
SetupBufferUploads ( ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
SCOPE_CYCLE_COUNTER ( STAT_RDG_CollectResourcesTime ) ;
CSV_SCOPED_TIMING_STAT_EXCLUSIVE ( RDG_CollectResources ) ;
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::CollectResources " , FColor : : Magenta ) ;
2020-09-24 00:43:27 -04:00
2022-04-22 17:11:57 -04:00
UniformBuffersToCreate . Reserve ( UniformBuffers . Num ( ) ) ;
2022-01-31 15:55:31 -05:00
EnumerateExtendedLifetimeResources ( Textures , [ ] ( FRDGTexture * Texture )
2020-07-06 18:58:26 -04:00
{
2022-01-31 15:55:31 -05:00
+ + Texture - > ReferenceCount ;
} ) ;
EnumerateExtendedLifetimeResources ( Buffers , [ ] ( FRDGBuffer * Buffer )
{
+ + Buffer - > ReferenceCount ;
} ) ;
2022-03-25 11:19:10 -04:00
// Null out any culled external resources so that the reference is freed up.
2022-04-22 17:11:57 -04:00
2022-03-25 11:19:10 -04:00
for ( const auto & Pair : ExternalTextures )
{
FRDGTexture * Texture = Pair . Value ;
if ( Texture - > bCulled )
{
check ( Texture - > ReferenceCount = = 0 ) ;
EndResourceRHI ( ProloguePassHandle , Texture , 0 ) ;
}
}
for ( const auto & Pair : ExternalBuffers )
{
FRDGBuffer * Buffer = Pair . Value ;
if ( Buffer - > bCulled )
{
check ( Buffer - > ReferenceCount = = 0 ) ;
EndResourceRHI ( ProloguePassHandle , Buffer , 0 ) ;
}
}
2022-01-31 15:55:31 -05:00
for ( FRDGPassHandle PassHandle = Passes . Begin ( ) ; PassHandle < ProloguePassHandle ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( ! Pass - > bCulled )
2020-09-24 00:43:27 -04:00
{
2022-01-31 15:55:31 -05:00
EndResourcesRHI ( Pass , ProloguePassHandle ) ;
2020-09-24 00:43:27 -04:00
}
}
2022-01-31 15:55:31 -05:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle ; PassHandle < = EpiloguePassHandle ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( ! Pass - > bCulled )
2021-05-19 17:54:58 -04:00
{
2022-01-31 15:55:31 -05:00
BeginResourcesRHI ( Pass , PassHandle ) ;
EndResourcesRHI ( Pass , PassHandle ) ;
2021-05-19 17:54:58 -04:00
}
2020-09-24 00:43:27 -04:00
}
2022-01-31 15:55:31 -05:00
EnumerateExtendedLifetimeResources ( Textures , [ & ] ( FRDGTextureRef Texture )
{
EndResourceRHI ( EpiloguePassHandle , Texture , 1 ) ;
} ) ;
EnumerateExtendedLifetimeResources ( Buffers , [ & ] ( FRDGBufferRef Buffer )
{
EndResourceRHI ( EpiloguePassHandle , Buffer , 1 ) ;
} ) ;
if ( TransientResourceAllocator )
{
# if RDG_ENABLE_TRACE
TransientResourceAllocator - > Flush ( RHICmdList , Trace . IsEnabled ( ) ? & Trace . TransientAllocationStats : nullptr ) ;
# else
TransientResourceAllocator - > Flush ( RHICmdList ) ;
# endif
}
2020-09-24 00:43:27 -04:00
}
{
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::CollectBarriers " , FColor : : Magenta ) ;
2020-09-24 00:43:27 -04:00
SCOPE_CYCLE_COUNTER ( STAT_RDG_CollectBarriersTime ) ;
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL ( RDG_CollectBarriers , GRDGVerboseCSVStats ! = 0 ) ;
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle + 1 ; PassHandle < EpiloguePassHandle ; + + PassHandle )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( ! Pass - > bCulled & & ! Pass - > bEmptyParameters )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
CollectPassBarriers ( Pass , PassHandle ) ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
}
}
}
{
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::Finalize " , FColor : : Magenta ) ;
2021-05-05 11:58:15 -04:00
2022-03-25 11:19:10 -04:00
EpilogueResourceAccesses . Reserve ( Textures . Num ( ) + Buffers . Num ( ) ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
Textures . Enumerate ( [ & ] ( FRDGTextureRef Texture )
2020-09-24 00:43:27 -04:00
{
2022-03-25 11:19:10 -04:00
AddEpilogueTransition ( Texture ) ;
2021-05-19 17:54:58 -04:00
} ) ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
Buffers . Enumerate ( [ & ] ( FRDGBufferRef Buffer )
2020-07-06 18:58:26 -04:00
{
2022-03-25 11:19:10 -04:00
AddEpilogueTransition ( Buffer ) ;
2021-05-19 17:54:58 -04:00
} ) ;
}
2020-07-06 18:58:26 -04:00
2021-07-22 12:43:00 -04:00
if ( bParallelExecuteEnabled )
{
// Overlap pass barrier creation with other compilation tasks, since it's not required to run on the render thread.
AsyncCompileEvents . Emplace ( FFunctionGraphTask : : CreateAndDispatchWhenReady (
[ this ] ( ENamedThreads : : Type , const FGraphEventRef & )
{
CreatePassBarriers ( ) ;
2021-05-19 17:54:58 -04:00
2021-07-22 12:43:00 -04:00
} , TStatId ( ) , nullptr , ENamedThreads : : AnyHiPriThreadHiPriTask ) ) ;
}
else
{
CreatePassBarriers ( ) ;
}
SubmitBufferUploads ( ) ;
CreateUniformBuffers ( ) ;
EndFlushResourcesRHI ( ) ;
2021-05-19 17:54:58 -04:00
2022-01-31 15:55:31 -05:00
IF_RDG_ENABLE_TRACE ( Trace . OutputGraphBegin ( ) ) ;
2020-07-06 18:58:26 -04:00
2021-07-29 13:02:16 -04:00
IF_RDG_ENABLE_DEBUG ( GRDGAllowRHIAccess = bParallelExecuteEnabled ) ;
2021-07-22 12:43:00 -04:00
const ENamedThreads : : Type RenderThread = ENamedThreads : : GetRenderThread_Local ( ) ;
FGraphEventRef DispatchParallelExecuteEvent ;
2021-03-17 12:44:59 -04:00
if ( ! IsImmediateMode ( ) )
2020-07-06 18:58:26 -04:00
{
2021-07-14 11:51:24 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::ExecutePasses " , FColor : : Magenta ) ;
2021-07-13 12:38:37 -04:00
SCOPE_CYCLE_COUNTER ( STAT_RDG_ExecuteTime ) ;
2021-05-19 17:54:58 -04:00
CSV_SCOPED_TIMING_STAT_EXCLUSIVE ( RenderOther ) ;
2020-07-06 18:58:26 -04:00
2021-07-22 12:43:00 -04:00
// Wait on all async compilation tasks before executing any passes.
if ( ! AsyncCompileEvents . IsEmpty ( ) )
{
FTaskGraphInterface : : Get ( ) . WaitUntilTasksComplete ( AsyncCompileEvents , RenderThread ) ;
}
2021-07-13 12:38:37 -04:00
if ( bParallelExecuteEnabled )
{
2021-07-22 12:43:00 -04:00
DispatchParallelExecuteEvent = FFunctionGraphTask : : CreateAndDispatchWhenReady (
[ this , & RHICmdContext = RHICmdList . GetContext ( ) ] ( ENamedThreads : : Type , const FGraphEventRef & )
2021-07-13 12:38:37 -04:00
{
2021-07-22 12:43:00 -04:00
DispatchParallelExecute ( & RHICmdContext ) ;
2021-07-13 12:38:37 -04:00
2021-07-22 12:43:00 -04:00
} , TStatId ( ) , nullptr , ENamedThreads : : AnyHiPriThreadHiPriTask ) ;
2021-07-13 12:38:37 -04:00
}
2021-05-19 17:54:58 -04:00
for ( FRDGPassHandle PassHandle = ProloguePassHandle ; PassHandle < = EpiloguePassHandle ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
2021-07-13 12:38:37 -04:00
if ( Pass - > bCulled )
2021-05-19 17:54:58 -04:00
{
2021-07-13 12:38:37 -04:00
# if STATS
GRDGStatPassCullCount + + ;
# endif
continue ;
2021-05-19 17:54:58 -04:00
}
2021-07-13 12:38:37 -04:00
if ( bParallelExecuteEnabled )
{
if ( Pass - > bParallelExecute )
{
# if RDG_CPU_SCOPES // CPU scopes are replayed on the render thread prior to executing the entire batch.
Pass - > CPUScopeOps . Execute ( ) ;
# endif
2021-07-23 10:18:32 -04:00
if ( Pass - > bParallelExecuteBegin )
2021-07-13 12:38:37 -04:00
{
FParallelPassSet & ParallelPassSet = ParallelPassSets [ Pass - > ParallelPassSetIndex ] ;
2021-07-22 12:43:00 -04:00
// Busy wait until our pass set is ready. This will be set by the dispatch task.
while ( ! FPlatformAtomics : : AtomicRead ( & ParallelPassSet . bInitialized ) ) { } ;
check ( ParallelPassSet . Event ! = nullptr & & ParallelPassSet . RHICmdList ! = nullptr ) ;
2021-07-13 12:38:37 -04:00
RHICmdList . QueueRenderThreadCommandListSubmit ( ParallelPassSet . Event , ParallelPassSet . RHICmdList ) ;
2021-07-23 10:18:32 -04:00
2021-10-12 21:21:22 -04:00
IF_RHI_WANT_BREADCRUMB_EVENTS ( RHICmdList . ImportBreadcrumbState ( * ParallelPassSet . BreadcrumbStateEnd ) ) ;
2021-07-23 10:18:32 -04:00
if ( ParallelPassSet . bDispatchAfterExecute & & IsRunningRHIInSeparateThread ( ) )
{
RHICmdList . ImmediateFlush ( EImmediateFlushType : : DispatchToRHIThread ) ;
}
2021-07-13 12:38:37 -04:00
}
continue ;
}
}
else if ( ! Pass - > bSentinel )
{
CompilePassOps ( Pass ) ;
}
FRHIComputeCommandList & RHICmdListPass = Pass - > Pipeline = = ERHIPipeline : : AsyncCompute
? static_cast < FRHIComputeCommandList & > ( RHICmdListAsyncCompute )
: RHICmdList ;
ExecutePass ( Pass , RHICmdListPass ) ;
2021-05-19 17:54:58 -04:00
}
2020-07-06 18:58:26 -04:00
}
else
{
2021-07-13 12:38:37 -04:00
ExecutePass ( EpiloguePass , RHICmdList ) ;
2020-07-06 18:58:26 -04:00
}
2021-07-22 12:43:00 -04:00
// Wait for the parallel dispatch task before attempting to wait on the execute event array (the former mutates the array).
if ( DispatchParallelExecuteEvent )
{
DispatchParallelExecuteEvent - > Wait ( RenderThread ) ;
}
2022-01-31 15:55:31 -05:00
RHICmdList . SetStaticUniformBuffers ( { } ) ;
# if WITH_MGPU
if ( NameForTemporalEffect ! = NAME_None )
2020-07-06 18:58:26 -04:00
{
2022-01-31 15:55:31 -05:00
TArray < FRHITexture * > BroadcastTexturesForTemporalEffect ;
2021-05-25 20:46:17 -04:00
for ( const FExtractedTexture & ExtractedTexture : ExtractedTextures )
2020-07-06 18:58:26 -04:00
{
2022-01-31 15:55:31 -05:00
if ( EnumHasAnyFlags ( ExtractedTexture . Texture - > Flags , ERDGTextureFlags : : MultiFrame ) )
{
BroadcastTexturesForTemporalEffect . Add ( ExtractedTexture . Texture - > GetRHIUnchecked ( ) ) ;
}
2020-07-06 18:58:26 -04:00
}
2022-01-31 15:55:31 -05:00
RHICmdList . BroadcastTemporalEffect ( NameForTemporalEffect , BroadcastTexturesForTemporalEffect ) ;
2021-05-19 17:54:58 -04:00
}
2022-01-31 15:55:31 -05:00
if ( bForceCopyCrossGPU )
2020-07-06 18:58:26 -04:00
{
2022-01-31 15:55:31 -05:00
ForceCopyCrossGPU ( ) ;
2020-07-06 18:58:26 -04:00
}
2022-01-31 15:55:31 -05:00
# endif
2022-03-25 11:19:10 -04:00
RHICmdList . SetTrackedAccess ( EpilogueResourceAccesses ) ;
2022-01-31 15:55:31 -05:00
// Wait on the actual parallel execute tasks in the Execute call. When draining is okay to let them overlap with other graph setup.
// This also needs to be done before extraction of external resources to be consistent with non-parallel rendering.
if ( ! ParallelExecuteEvents . IsEmpty ( ) )
{
FTaskGraphInterface : : Get ( ) . WaitUntilTasksComplete ( ParallelExecuteEvents , RenderThread ) ;
}
for ( const FExtractedTexture & ExtractedTexture : ExtractedTextures )
{
2022-03-25 11:19:10 -04:00
check ( ExtractedTexture . Texture - > RenderTarget ) ;
* ExtractedTexture . PooledTexture = ExtractedTexture . Texture - > RenderTarget ;
2022-01-31 15:55:31 -05:00
}
for ( const FExtractedBuffer & ExtractedBuffer : ExtractedBuffers )
{
check ( ExtractedBuffer . Buffer - > PooledBuffer ) ;
* ExtractedBuffer . PooledBuffer = ExtractedBuffer . Buffer - > PooledBuffer ;
}
IF_RDG_ENABLE_TRACE ( Trace . OutputGraphEnd ( * this ) ) ;
IF_RDG_GPU_SCOPES ( GPUScopeStacks . Graphics . EndExecute ( RHICmdList ) ) ;
IF_RDG_GPU_SCOPES ( GPUScopeStacks . AsyncCompute . EndExecute ( RHICmdListAsyncCompute ) ) ;
IF_RDG_CPU_SCOPES ( CPUScopeStacks . EndExecute ( ) ) ;
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExecuteEnd ( ) ) ;
IF_RDG_ENABLE_DEBUG ( GRDGAllowRHIAccess = false ) ;
# if STATS
GRDGStatBufferCount + = Buffers . Num ( ) ;
GRDGStatTextureCount + = Textures . Num ( ) ;
GRDGStatViewCount + = Views . Num ( ) ;
GRDGStatMemoryWatermark = FMath : : Max ( GRDGStatMemoryWatermark , Allocator . GetByteCount ( ) ) ;
# endif
2020-07-06 18:58:26 -04:00
2021-07-29 13:02:16 -04:00
RasterPassCount = 0 ;
AsyncComputePassCount = 0 ;
2020-07-06 18:58:26 -04:00
2021-07-22 12:43:00 -04:00
// Flush any outstanding async compute commands at the end to get things moving down the pipe.
2021-07-13 12:38:37 -04:00
if ( RHICmdListAsyncCompute . HasCommands ( ) )
{
FRHIAsyncComputeCommandListImmediate : : ImmediateDispatch ( RHICmdListAsyncCompute ) ;
}
2020-07-06 18:58:26 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
FRDGPass * FRDGBuilder : : SetupPass ( FRDGPass * Pass )
2020-07-06 18:58:26 -04:00
{
2022-05-04 12:41:19 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateAddPass ( Pass , InAuxiliaryPass ( ) ) ) ;
2021-05-19 17:54:58 -04:00
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL ( RDGBuilder_SetupPass , GRDGVerboseCSVStats ! = 0 ) ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
const FRDGParameterStruct PassParameters = Pass - > GetParameters ( ) ;
2021-05-19 17:54:58 -04:00
const FRDGPassHandle PassHandle = Pass - > Handle ;
const ERDGPassFlags PassFlags = Pass - > Flags ;
const ERHIPipeline PassPipeline = Pass - > Pipeline ;
2020-07-06 18:58:26 -04:00
2021-03-17 12:44:59 -04:00
bool bRenderPassOnlyWrites = true ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
const auto TryAddView = [ & ] ( FRDGViewRef View )
{
if ( View & & View - > LastPass ! = PassHandle )
{
View - > LastPass = PassHandle ;
Pass - > Views . Add ( View - > Handle ) ;
}
} ;
Pass - > Views . Reserve ( PassParameters . GetBufferParameterCount ( ) + PassParameters . GetTextureParameterCount ( ) ) ;
2020-09-24 00:43:27 -04:00
Pass - > TextureStates . Reserve ( PassParameters . GetTextureParameterCount ( ) + ( PassParameters . HasRenderTargets ( ) ? ( MaxSimultaneousRenderTargets + 1 ) : 0 ) ) ;
2021-03-17 12:44:59 -04:00
EnumerateTextureAccess ( PassParameters , PassFlags , [ & ] ( FRDGViewRef TextureView , FRDGTextureRef Texture , ERHIAccess Access , ERDGTextureAccessFlags AccessFlags , FRDGTextureSubresourceRange Range )
2020-07-06 18:58:26 -04:00
{
2021-05-05 11:58:15 -04:00
TryAddView ( TextureView ) ;
2022-04-25 13:00:12 -04:00
if ( Texture - > AccessModeState . IsExternalAccess ( ) )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
// Resources in external access mode are expected to remain in the same state and are ignored by the graph.
// As only External | Extracted resources can be set as external by the user, the graph doesn't need to track
// them any more for culling / transition purposes. Validation checks that these invariants are true.
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExternalAccess ( Texture , Access , Pass ) ) ;
2021-04-06 11:45:09 -04:00
return ;
}
2022-05-04 17:36:33 -04:00
// Use the whole texture range for copy states on RHI's that don't track them separately
if ( ! GRHISupportsSeparateDepthStencilCopyAccess )
{
const ERHIAccess AnyCopyAccess = ERHIAccess : : CopySrc | ERHIAccess : : CopyDest ;
if ( ( Texture - > Desc . Format = = PF_DepthStencil ) & & EnumHasAnyFlags ( Access , AnyCopyAccess ) )
{
Range = Texture - > GetSubresourceRange ( ) ; // WholeRange
}
}
2020-09-24 00:43:27 -04:00
const FRDGViewHandle NoUAVBarrierHandle = GetHandleIfNoUAVBarrier ( TextureView ) ;
2020-10-09 22:42:26 -04:00
const EResourceTransitionFlags TransitionFlags = GetTextureViewTransitionFlags ( TextureView , Texture ) ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
FRDGPass : : FTextureState * PassState ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
if ( Texture - > LastPass ! = PassHandle )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
Texture - > LastPass = PassHandle ;
2022-01-07 10:39:08 -05:00
Texture - > PassStateIndex = static_cast < uint16 > ( Pass - > TextureStates . Num ( ) ) ;
2020-12-07 18:45:31 -04:00
2021-05-05 11:58:15 -04:00
PassState = & Pass - > TextureStates . Emplace_GetRef ( Texture ) ;
2020-09-24 00:43:27 -04:00
}
2021-05-05 11:58:15 -04:00
else
{
PassState = & Pass - > TextureStates [ Texture - > PassStateIndex ] ;
}
PassState - > ReferenceCount + + ;
2020-09-24 00:43:27 -04:00
const auto AddSubresourceAccess = [ & ] ( FRDGSubresourceState & State )
{
State . Access = MakeValidAccess ( State . Access | Access ) ;
State . Flags | = TransitionFlags ;
State . NoUAVBarrierFilter . AddHandle ( NoUAVBarrierHandle ) ;
2020-11-11 19:22:36 -04:00
State . SetPass ( PassPipeline , PassHandle ) ;
2020-09-24 00:43:27 -04:00
} ;
2021-05-05 11:58:15 -04:00
if ( IsWholeResource ( PassState - > State ) )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
AddSubresourceAccess ( GetWholeResource ( PassState - > State ) ) ;
2020-09-24 00:43:27 -04:00
}
else
{
2021-05-05 11:58:15 -04:00
EnumerateSubresourceRange ( PassState - > State , Texture - > Layout , Range , AddSubresourceAccess ) ;
2020-09-24 00:43:27 -04:00
}
2021-03-17 12:44:59 -04:00
const bool bWritableAccess = IsWritableAccess ( Access ) ;
bRenderPassOnlyWrites & = ( ! bWritableAccess | | EnumHasAnyFlags ( AccessFlags , ERDGTextureAccessFlags : : RenderTarget ) ) ;
Texture - > bProduced | = bWritableAccess ;
2020-07-06 18:58:26 -04:00
} ) ;
2020-09-24 00:43:27 -04:00
Pass - > BufferStates . Reserve ( PassParameters . GetBufferParameterCount ( ) ) ;
EnumerateBufferAccess ( PassParameters , PassFlags , [ & ] ( FRDGViewRef BufferView , FRDGBufferRef Buffer , ERHIAccess Access )
2020-07-06 18:58:26 -04:00
{
2021-05-05 11:58:15 -04:00
TryAddView ( BufferView ) ;
2020-07-06 18:58:26 -04:00
2022-04-25 13:00:12 -04:00
if ( Buffer - > AccessModeState . IsExternalAccess ( ) )
2021-04-06 11:45:09 -04:00
{
2022-04-25 13:00:12 -04:00
// Resources in external access mode are expected to remain in the same state and are ignored by the graph.
// As only External | Extracted resources can be set as external by the user, the graph doesn't need to track
// them any more for culling / transition purposes. Validation checks that these invariants are true.
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExternalAccess ( Buffer , Access , Pass ) ) ;
2021-04-06 11:45:09 -04:00
return ;
}
2020-09-24 00:43:27 -04:00
const FRDGViewHandle NoUAVBarrierHandle = GetHandleIfNoUAVBarrier ( BufferView ) ;
2021-05-05 11:58:15 -04:00
FRDGPass : : FBufferState * PassState ;
if ( Buffer - > LastPass ! = PassHandle )
{
Buffer - > LastPass = PassHandle ;
Buffer - > PassStateIndex = Pass - > BufferStates . Num ( ) ;
PassState = & Pass - > BufferStates . Emplace_GetRef ( Buffer ) ;
}
else
{
PassState = & Pass - > BufferStates [ Buffer - > PassStateIndex ] ;
}
PassState - > ReferenceCount + + ;
PassState - > State . Access = MakeValidAccess ( PassState - > State . Access | Access ) ;
PassState - > State . NoUAVBarrierFilter . AddHandle ( NoUAVBarrierHandle ) ;
PassState - > State . SetPass ( PassPipeline , PassHandle ) ;
2020-09-24 00:43:27 -04:00
2021-03-17 12:44:59 -04:00
const bool bWritableAccess = IsWritableAccess ( Access ) ;
bRenderPassOnlyWrites & = ! bWritableAccess ;
Buffer - > bProduced | = bWritableAccess ;
2020-07-06 18:58:26 -04:00
} ) ;
2021-06-01 17:25:18 -04:00
Pass - > UniformBuffers . Reserve ( PassParameters . GetUniformBufferParameterCount ( ) ) ;
2021-05-05 11:58:15 -04:00
PassParameters . EnumerateUniformBuffers ( [ & ] ( FRDGUniformBufferBinding UniformBuffer )
{
2021-06-01 17:25:18 -04:00
Pass - > UniformBuffers . Emplace ( UniformBuffer . GetUniformBuffer ( ) - > Handle ) ;
2021-05-05 11:58:15 -04:00
} ) ;
2021-03-17 12:44:59 -04:00
Pass - > bRenderPassOnlyWrites = bRenderPassOnlyWrites ;
2021-05-05 11:58:15 -04:00
Pass - > bHasExternalOutputs = PassParameters . HasExternalOutputs ( ) ;
2020-09-24 00:43:27 -04:00
const bool bEmptyParameters = ! Pass - > TextureStates . Num ( ) & & ! Pass - > BufferStates . Num ( ) ;
2021-05-19 17:54:58 -04:00
SetupPassInternal ( Pass , PassHandle , PassPipeline , bEmptyParameters ) ;
return Pass ;
2020-09-24 00:43:27 -04:00
}
2021-05-19 17:54:58 -04:00
FRDGPass * FRDGBuilder : : SetupEmptyPass ( FRDGPass * Pass )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
const bool bEmptyParameters = true ;
SetupPassInternal ( Pass , Pass - > Handle , Pass - > Pipeline , bEmptyParameters ) ;
return Pass ;
2020-09-24 00:43:27 -04:00
}
2021-07-13 12:38:37 -04:00
void FRDGBuilder : : CompilePassOps ( FRDGPass * Pass )
{
# if WITH_MGPU
if ( ! bWaitedForTemporalEffect & & NameForTemporalEffect ! = NAME_None & & Pass - > Pipeline = = ERHIPipeline : : Graphics )
{
bWaitedForTemporalEffect = true ;
Pass - > bWaitForTemporalEffect = 1 ;
}
FRHIGPUMask GPUMask = Pass - > GPUMask ;
# else
FRHIGPUMask GPUMask = FRHIGPUMask : : All ( ) ;
# endif
# if RDG_CMDLIST_STATS
if ( CommandListStatState ! = Pass - > CommandListStat & & ! Pass - > bSentinel )
{
CommandListStatState = Pass - > CommandListStat ;
Pass - > bSetCommandListStat = 1 ;
}
# endif
# if RDG_CPU_SCOPES
Pass - > CPUScopeOps = CPUScopeStacks . CompilePassPrologue ( Pass ) ;
# endif
# if RDG_GPU_SCOPES
Pass - > GPUScopeOpsPrologue = GPUScopeStacks . CompilePassPrologue ( Pass , GPUMask ) ;
Pass - > GPUScopeOpsEpilogue = GPUScopeStacks . CompilePassEpilogue ( Pass ) ;
# endif
}
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : SetupPassInternal ( FRDGPass * Pass , FRDGPassHandle PassHandle , ERHIPipeline PassPipeline , bool bEmptyParameters )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
check ( Pass - > Handle = = PassHandle ) ;
check ( Pass - > Pipeline = = PassPipeline ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
Pass - > bEmptyParameters = bEmptyParameters ;
Pass - > bDispatchAfterExecute = bDispatchHint ;
2020-09-24 00:43:27 -04:00
Pass - > GraphicsForkPass = PassHandle ;
2021-05-19 17:54:58 -04:00
Pass - > GraphicsJoinPass = PassHandle ;
2020-09-24 00:43:27 -04:00
Pass - > PrologueBarrierPass = PassHandle ;
Pass - > EpilogueBarrierPass = PassHandle ;
2021-05-19 17:54:58 -04:00
bDispatchHint = false ;
if ( ! EnumHasAnyFlags ( Pass - > Flags , ERDGPassFlags : : AsyncCompute ) )
2021-05-05 11:58:15 -04:00
{
2021-05-19 17:54:58 -04:00
Pass - > ResourcesToBegin . Add ( Pass ) ;
Pass - > ResourcesToEnd . Add ( Pass ) ;
2021-05-05 11:58:15 -04:00
}
2021-05-19 17:54:58 -04:00
AsyncComputePassCount + = EnumHasAnyFlags ( Pass - > Flags , ERDGPassFlags : : AsyncCompute ) ? 1 : 0 ;
RasterPassCount + = EnumHasAnyFlags ( Pass - > Flags , ERDGPassFlags : : Raster ) ? 1 : 0 ;
2020-09-24 00:43:27 -04:00
# if WITH_MGPU
Pass - > GPUMask = RHICmdList . GetGPUMask ( ) ;
# endif
2020-11-30 13:27:08 -04:00
# if STATS
2021-05-19 17:54:58 -04:00
Pass - > CommandListStat = CommandListStatScope ;
GRDGStatPassCount + + ;
GRDGStatPassWithParameterCount + = ! bEmptyParameters ? 1 : 0 ;
2020-11-30 13:27:08 -04:00
# endif
2020-09-24 00:43:27 -04:00
IF_RDG_CPU_SCOPES ( Pass - > CPUScopes = CPUScopeStacks . GetCurrentScopes ( ) ) ;
IF_RDG_GPU_SCOPES ( Pass - > GPUScopes = GPUScopeStacks . GetCurrentScopes ( PassPipeline ) ) ;
2021-02-03 13:17:04 -04:00
# if RDG_GPU_SCOPES && RDG_ENABLE_TRACE
Pass - > TraceEventScope = GPUScopeStacks . GetCurrentScopes ( ERHIPipeline : : Graphics ) . Event ;
# endif
2020-09-24 00:43:27 -04:00
# if RDG_GPU_SCOPES && RDG_ENABLE_DEBUG
if ( const FRDGEventScope * Scope = Pass - > GPUScopes . Event )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
Pass - > FullPathIfDebug = Scope - > GetPath ( Pass - > Name ) ;
}
# endif
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
if ( IsImmediateMode ( ) & & ! Pass - > bSentinel )
2020-09-24 00:43:27 -04:00
{
2021-07-13 12:38:37 -04:00
SCOPED_NAMED_EVENT ( FRDGBuilder_ExecutePass , FColor : : Emerald ) ;
2021-05-05 11:58:15 -04:00
RDG_ALLOW_RHI_ACCESS_SCOPE ( ) ;
2021-03-17 12:44:59 -04:00
2020-09-24 00:43:27 -04:00
// Trivially redirect the merge states to the pass states, since we won't be compiling the graph.
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > TextureStates )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
const uint32 SubresourceCount = PassState . State . Num ( ) ;
PassState . MergeState . SetNum ( SubresourceCount ) ;
for ( uint32 Index = 0 ; Index < SubresourceCount ; + + Index )
{
if ( PassState . State [ Index ] . Access ! = ERHIAccess : : Unknown )
{
PassState . MergeState [ Index ] = & PassState . State [ Index ] ;
}
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
for ( auto & PassState : Pass - > BufferStates )
2020-09-24 00:43:27 -04:00
{
PassState . MergeState = & PassState . State ;
}
check ( ! EnumHasAnyFlags ( PassPipeline , ERHIPipeline : : AsyncCompute ) ) ;
2021-03-17 12:44:59 -04:00
2021-07-22 12:43:00 -04:00
SetupBufferUploads ( ) ;
2021-07-13 12:38:37 -04:00
SubmitBufferUploads ( ) ;
CompilePassOps ( Pass ) ;
2021-05-19 17:54:58 -04:00
BeginResourcesRHI ( Pass , PassHandle ) ;
CollectPassBarriers ( Pass , PassHandle ) ;
CreatePassBarriers ( ) ;
CreateUniformBuffers ( ) ;
2021-07-13 12:38:37 -04:00
ExecutePass ( Pass , RHICmdList ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
IF_RDG_ENABLE_DEBUG ( VisualizePassOutputs ( Pass ) ) ;
2021-12-03 02:41:52 -05:00
2022-04-22 17:11:57 -04:00
# if RDG_DUMP_RESOURCES
DumpResourcePassOutputs ( Pass ) ;
# endif
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-07-22 12:43:00 -04:00
void FRDGBuilder : : SetupBufferUploads ( )
2021-05-25 20:46:17 -04:00
{
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::PrepareBufferUploads " , FColor : : Magenta ) ;
2021-05-25 20:46:17 -04:00
for ( FUploadedBuffer & UploadedBuffer : UploadedBuffers )
{
2021-09-01 03:09:25 -04:00
if ( UploadedBuffer . bUseDataCallbacks )
2021-06-07 12:19:06 -04:00
{
2021-07-22 12:43:00 -04:00
UploadedBuffer . Data = UploadedBuffer . DataCallback ( ) ;
UploadedBuffer . DataSize = UploadedBuffer . DataSizeCallback ( ) ;
2021-06-07 12:19:06 -04:00
}
2021-07-22 12:43:00 -04:00
if ( UploadedBuffer . Data & & UploadedBuffer . DataSize )
2021-06-07 12:19:06 -04:00
{
2021-07-22 12:43:00 -04:00
ConvertToExternalBuffer ( UploadedBuffer . Buffer ) ;
2022-04-22 17:11:57 -04:00
check ( UploadedBuffer . DataSize < = UploadedBuffer . Buffer - > Desc . GetSize ( ) ) ;
2021-07-22 12:43:00 -04:00
}
}
}
void FRDGBuilder : : SubmitBufferUploads ( )
{
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::SubmitBufferUploads " , FColor : : Magenta ) ;
for ( const FUploadedBuffer & UploadedBuffer : UploadedBuffers )
{
if ( UploadedBuffer . Data & & UploadedBuffer . DataSize )
{
2021-07-22 22:31:13 -04:00
# if PLATFORM_NEEDS_GPU_UAV_RESOURCE_INIT_WORKAROUND
if ( UploadedBuffer . Buffer - > bUAVAccessed )
{
FRHIResourceCreateInfo CreateInfo ( UploadedBuffer . Buffer - > Name ) ;
FBufferRHIRef TempBuffer = RHICreateVertexBuffer ( UploadedBuffer . DataSize , BUF_Static | BUF_ShaderResource , CreateInfo ) ;
void * DestPtr = RHICmdList . LockBuffer ( TempBuffer , 0 , UploadedBuffer . DataSize , RLM_WriteOnly ) ;
FMemory : : Memcpy ( DestPtr , UploadedBuffer . Data , UploadedBuffer . DataSize ) ;
RHICmdList . UnlockBuffer ( TempBuffer ) ;
2021-07-29 13:02:16 -04:00
RHICmdList . Transition (
{
FRHITransitionInfo ( TempBuffer , ERHIAccess : : Unknown , ERHIAccess : : CopySrc | ERHIAccess : : SRVMask ) ,
FRHITransitionInfo ( UploadedBuffer . Buffer - > GetRHI ( ) , ERHIAccess : : Unknown , ERHIAccess : : CopyDest )
} ) ;
2021-07-22 22:31:13 -04:00
RHICmdList . CopyBufferRegion ( UploadedBuffer . Buffer - > GetRHI ( ) , 0 , TempBuffer , 0 , UploadedBuffer . DataSize ) ;
}
else
# endif
{
void * DestPtr = RHICmdList . LockBuffer ( UploadedBuffer . Buffer - > GetRHI ( ) , 0 , UploadedBuffer . DataSize , RLM_WriteOnly ) ;
FMemory : : Memcpy ( DestPtr , UploadedBuffer . Data , UploadedBuffer . DataSize ) ;
RHICmdList . UnlockBuffer ( UploadedBuffer . Buffer - > GetRHI ( ) ) ;
}
2021-09-01 03:09:25 -04:00
if ( UploadedBuffer . bUseFreeCallbacks )
{
UploadedBuffer . DataFreeCallback ( UploadedBuffer . Data ) ;
}
2021-06-07 12:19:06 -04:00
}
2021-05-25 20:46:17 -04:00
}
UploadedBuffers . Reset ( ) ;
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-07-22 12:43:00 -04:00
void FRDGBuilder : : SetupParallelExecute ( )
{
SCOPED_NAMED_EVENT ( SetupParallelExecute , FColor : : Emerald ) ;
FTaskTagScope Scope ( ETaskTag : : EParallelRenderingThread ) ;
TArray < FRDGPass * , TInlineAllocator < 64 , FRDGArrayAllocator > > ParallelPassCandidates ;
int32 MergedRenderPassCandidates = 0 ;
2021-07-23 10:18:32 -04:00
bool bDispatchAfterExecute = false ;
2021-07-22 12:43:00 -04:00
const auto FlushParallelPassCandidates = [ & ] ( )
{
if ( ParallelPassCandidates . IsEmpty ( ) )
{
return ;
}
int32 PassBeginIndex = 0 ;
int32 PassEndIndex = ParallelPassCandidates . Num ( ) ;
// It's possible that the first pass is inside a merged RHI render pass region. If so, we must push it forward until after the render pass ends.
if ( const FRDGPass * FirstPass = ParallelPassCandidates [ PassBeginIndex ] ; FirstPass - > PrologueBarrierPass < FirstPass - > Handle )
{
const FRDGPass * EpilogueBarrierPass = Passes [ FirstPass - > EpilogueBarrierPass ] ;
for ( ; PassBeginIndex < ParallelPassCandidates . Num ( ) ; + + PassBeginIndex )
{
if ( ParallelPassCandidates [ PassBeginIndex ] = = EpilogueBarrierPass )
{
+ + PassBeginIndex ;
break ;
}
}
}
if ( PassBeginIndex < PassEndIndex )
{
// It's possible that the last pass is inside a merged RHI render pass region. If so, we must push it backwards until after the render pass begins.
if ( FRDGPass * LastPass = ParallelPassCandidates . Last ( ) ; LastPass - > EpilogueBarrierPass > LastPass - > Handle )
{
FRDGPass * PrologueBarrierPass = Passes [ LastPass - > PrologueBarrierPass ] ;
while ( PassEndIndex > PassBeginIndex )
{
if ( ParallelPassCandidates [ - - PassEndIndex ] = = PrologueBarrierPass )
{
break ;
}
}
}
}
const int32 ParallelPassCandidateCount = PassEndIndex - PassBeginIndex ;
if ( ParallelPassCandidateCount > = GRDGParallelExecutePassMin )
{
FRDGPass * PassBegin = ParallelPassCandidates [ PassBeginIndex ] ;
PassBegin - > bParallelExecuteBegin = 1 ;
2021-07-23 10:18:32 -04:00
PassBegin - > ParallelPassSetIndex = ParallelPassSets . Num ( ) ;
2021-07-22 12:43:00 -04:00
FRDGPass * PassEnd = ParallelPassCandidates [ PassEndIndex - 1 ] ;
PassEnd - > bParallelExecuteEnd = 1 ;
2021-10-12 21:21:22 -04:00
PassEnd - > ParallelPassSetIndex = ParallelPassSets . Num ( ) ;
2021-07-22 12:43:00 -04:00
for ( int32 PassIndex = PassBeginIndex ; PassIndex < PassEndIndex ; + + PassIndex )
{
ParallelPassCandidates [ PassIndex ] - > bParallelExecute = 1 ;
}
2021-10-12 21:21:22 -04:00
FParallelPassSet & ParallelPassSet = ParallelPassSets . Emplace_GetRef ( ) ;
ParallelPassSet . Passes . Append ( ParallelPassCandidates . GetData ( ) + PassBeginIndex , ParallelPassCandidateCount ) ;
ParallelPassSet . bDispatchAfterExecute = bDispatchAfterExecute ;
2021-07-22 12:43:00 -04:00
}
ParallelPassCandidates . Reset ( ) ;
MergedRenderPassCandidates = 0 ;
2021-07-23 10:18:32 -04:00
bDispatchAfterExecute = false ;
2021-07-22 12:43:00 -04:00
} ;
ParallelPassSets . Reserve ( 32 ) ;
2022-01-31 15:55:31 -05:00
ParallelPassCandidates . Emplace ( ProloguePass ) ;
2021-07-22 12:43:00 -04:00
for ( FRDGPassHandle PassHandle = GetProloguePassHandle ( ) + 1 ; PassHandle < GetEpiloguePassHandle ( ) ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( Pass - > bCulled )
{
continue ;
}
CompilePassOps ( Pass ) ;
if ( Pass - > Pipeline = = ERHIPipeline : : AsyncCompute )
{
2021-07-23 10:18:32 -04:00
if ( Pass - > bAsyncComputeEnd )
{
FlushParallelPassCandidates ( ) ;
}
2021-07-22 12:43:00 -04:00
continue ;
}
2022-02-03 09:15:49 -05:00
if ( ! Pass - > bParallelExecuteAllowed )
2021-07-22 12:43:00 -04:00
{
FlushParallelPassCandidates ( ) ;
continue ;
}
ParallelPassCandidates . Emplace ( Pass ) ;
2021-07-23 10:18:32 -04:00
bDispatchAfterExecute | = Pass - > bDispatchAfterExecute ;
2021-07-22 12:43:00 -04:00
// Don't count merged render passes for the maximum pass threshold. This avoids the case where
// a large merged render pass span could end up forcing it back onto the render thread, since
// it's not possible to launch a task for a subset of passes within a merged render pass.
MergedRenderPassCandidates + = Pass - > bSkipRenderPassBegin | Pass - > bSkipRenderPassEnd ;
if ( ParallelPassCandidates . Num ( ) - MergedRenderPassCandidates > = GRDGParallelExecutePassMax )
{
FlushParallelPassCandidates ( ) ;
}
}
2021-07-29 13:02:16 -04:00
ParallelPassCandidates . Emplace ( EpiloguePass ) ;
2021-07-22 12:43:00 -04:00
FlushParallelPassCandidates ( ) ;
2021-10-12 21:21:22 -04:00
# if RHI_WANT_BREADCRUMB_EVENTS
SCOPED_NAMED_EVENT ( BreadcrumbSetup , FColor : : Emerald ) ;
for ( FRDGPassHandle PassHandle = GetProloguePassHandle ( ) ; PassHandle < = GetEpiloguePassHandle ( ) ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
if ( Pass - > bCulled )
{
continue ;
}
if ( Pass - > bParallelExecuteBegin )
{
FParallelPassSet & ParallelPassSet = ParallelPassSets [ Pass - > ParallelPassSetIndex ] ;
ParallelPassSet . BreadcrumbStateBegin = BreadcrumbState - > Copy ( Allocator ) ;
ParallelPassSet . BreadcrumbStateEnd = ParallelPassSet . BreadcrumbStateBegin ;
}
Pass - > GPUScopeOpsPrologue . Event . Execute ( * BreadcrumbState ) ;
Pass - > GPUScopeOpsEpilogue . Event . Execute ( * BreadcrumbState ) ;
if ( Pass - > bParallelExecuteEnd )
{
FParallelPassSet & ParallelPassSet = ParallelPassSets [ Pass - > ParallelPassSetIndex ] ;
if ( ParallelPassSet . BreadcrumbStateEnd - > Version ! = BreadcrumbState - > Version )
{
ParallelPassSet . BreadcrumbStateEnd = BreadcrumbState - > Copy ( Allocator ) ;
}
}
}
# endif
2021-07-22 12:43:00 -04:00
}
void FRDGBuilder : : DispatchParallelExecute ( IRHICommandContext * RHICmdContext )
{
2021-07-29 13:02:16 -04:00
SCOPED_NAMED_EVENT ( DispatchParallelExecute , FColor : : Emerald ) ;
2021-07-22 12:43:00 -04:00
ParallelExecuteEvents . Reserve ( ParallelExecuteEvents . Num ( ) + ParallelPassSets . Num ( ) ) ;
2022-01-31 15:55:31 -05:00
for ( FParallelPassSet & ParallelPassSet : ParallelPassSets )
2021-07-22 12:43:00 -04:00
{
ParallelPassSet . RHICmdList = new FRHICommandList ( FRHIGPUMask : : All ( ) ) ;
ParallelPassSet . RHICmdList - > SetContext ( RHICmdContext ) ;
2021-10-12 21:21:22 -04:00
IF_RHI_WANT_BREADCRUMB_EVENTS ( ParallelPassSet . RHICmdList - > ImportBreadcrumbState ( * ParallelPassSet . BreadcrumbStateBegin ) ) ;
2021-07-22 12:43:00 -04:00
// Avoid referencing the parallel pass struct directly in the task, as the set can resize.
TArrayView < FRDGPass * > ParallelPasses = ParallelPassSet . Passes ;
ParallelPassSet . Event = FFunctionGraphTask : : CreateAndDispatchWhenReady (
[ this , ParallelPasses , & RHICmdListPass = * ParallelPassSet . RHICmdList ] ( ENamedThreads : : Type , const FGraphEventRef & MyCompletionGraphEvent )
{
SCOPED_NAMED_EVENT ( ParallelExecute , FColor : : Emerald ) ;
FTaskTagScope Scope ( ETaskTag : : EParallelRenderingThread ) ;
FMemMark MemMark ( FMemStack : : Get ( ) ) ;
for ( FRDGPass * Pass : ParallelPasses )
{
ExecutePass ( Pass , RHICmdListPass ) ;
}
RHICmdListPass . HandleRTThreadTaskCompletion ( MyCompletionGraphEvent ) ;
} , TStatId ( ) , nullptr , ENamedThreads : : AnyHiPriThreadHiPriTask ) ;
// Mark this set as initialized so that it can be submitted.
FPlatformAtomics : : AtomicStore ( & ParallelPassSet . bInitialized , 1 ) ;
// Enqueue the event to be synced at the end of RDG execution.
ParallelExecuteEvents . Emplace ( ParallelPassSet . Event ) ;
}
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : CreateUniformBuffers ( )
{
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::CreateUniformBuffers " , FColor : : Magenta ) ;
2021-05-19 17:54:58 -04:00
for ( FRDGUniformBufferHandle UniformBufferHandle : UniformBuffersToCreate )
{
UniformBuffers [ UniformBufferHandle ] - > InitRHI ( ) ;
}
UniformBuffersToCreate . Reset ( ) ;
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : AddProloguePass ( )
{
2022-01-31 15:55:31 -05:00
ProloguePass = SetupEmptyPass ( Passes . Allocate < FRDGSentinelPass > ( Allocator , RDG_EVENT_NAME ( " Graph Prologue (Graphics) " ) ) ) ;
2021-05-19 17:54:58 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2020-07-06 18:58:26 -04:00
void FRDGBuilder : : ExecutePassPrologue ( FRHIComputeCommandList & RHICmdListPass , FRDGPass * Pass )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL ( RDGBuilder_ExecutePassPrologue , GRDGVerboseCSVStats ! = 0 ) ;
2019-08-15 18:58:08 -04:00
2020-09-24 00:43:27 -04:00
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExecutePassBegin ( Pass ) ) ;
2021-05-19 17:54:58 -04:00
# if RDG_CMDLIST_STATS
2021-07-13 12:38:37 -04:00
if ( Pass - > bSetCommandListStat )
2021-05-19 17:54:58 -04:00
{
2021-07-13 12:38:37 -04:00
RHICmdListPass . SetCurrentStat ( Pass - > CommandListStat ) ;
2021-05-19 17:54:58 -04:00
}
# endif
const ERDGPassFlags PassFlags = Pass - > Flags ;
const ERHIPipeline PassPipeline = Pass - > Pipeline ;
2020-11-11 19:22:36 -04:00
2020-09-24 00:43:27 -04:00
if ( Pass - > PrologueBarriersToBegin )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchBegin ( Pass , * Pass - > PrologueBarriersToBegin ) ) ;
2020-11-11 19:22:36 -04:00
Pass - > PrologueBarriersToBegin - > Submit ( RHICmdListPass , PassPipeline ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2018-11-21 20:22:47 -05:00
2021-05-19 17:54:58 -04:00
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchEnd ( Pass , Pass - > PrologueBarriersToEnd ) ) ;
Pass - > PrologueBarriersToEnd . Submit ( RHICmdListPass , PassPipeline ) ;
2020-07-06 18:58:26 -04:00
2021-05-19 17:54:58 -04:00
if ( PassPipeline = = ERHIPipeline : : AsyncCompute & & ! Pass - > bSentinel & & AsyncComputeBudgetState ! = Pass - > AsyncComputeBudget )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
AsyncComputeBudgetState = Pass - > AsyncComputeBudget ;
2020-09-24 00:43:27 -04:00
RHICmdListPass . SetAsyncComputeBudget ( Pass - > AsyncComputeBudget ) ;
}
2020-07-06 18:58:26 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Raster ) )
{
2020-09-24 00:43:27 -04:00
if ( ! EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : SkipRenderPass ) & & ! Pass - > SkipRenderPassBegin ( ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
static_cast < FRHICommandList & > ( RHICmdListPass ) . BeginRenderPass ( Pass - > GetParameters ( ) . GetRenderPassInfo ( ) , Pass - > GetName ( ) ) ;
2020-07-06 18:58:26 -04:00
}
}
2020-11-30 13:27:08 -04:00
BeginUAVOverlap ( Pass , RHICmdListPass ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
void FRDGBuilder : : ExecutePassEpilogue ( FRHIComputeCommandList & RHICmdListPass , FRDGPass * Pass )
2018-11-21 20:22:47 -05:00
{
2020-09-24 00:43:27 -04:00
CSV_SCOPED_TIMING_STAT_EXCLUSIVE_CONDITIONAL ( RDGBuilder_ExecutePassEpilogue , GRDGVerboseCSVStats ! = 0 ) ;
2020-07-06 18:58:26 -04:00
2020-11-30 13:27:08 -04:00
EndUAVOverlap ( Pass , RHICmdListPass ) ;
2021-05-19 17:54:58 -04:00
const ERDGPassFlags PassFlags = Pass - > Flags ;
const ERHIPipeline PassPipeline = Pass - > Pipeline ;
2020-11-11 19:22:36 -04:00
const FRDGParameterStruct PassParameters = Pass - > GetParameters ( ) ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
if ( EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : Raster ) & & ! EnumHasAnyFlags ( PassFlags , ERDGPassFlags : : SkipRenderPass ) & & ! Pass - > SkipRenderPassEnd ( ) )
2018-11-21 20:22:47 -05:00
{
2020-07-06 18:58:26 -04:00
static_cast < FRHICommandList & > ( RHICmdListPass ) . EndRenderPass ( ) ;
2019-06-11 18:27:07 -04:00
}
2018-11-21 20:22:47 -05:00
2020-11-11 19:22:36 -04:00
FRDGTransitionQueue Transitions ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchBegin ( Pass , Pass - > EpilogueBarriersToBeginForGraphics ) ) ;
Pass - > EpilogueBarriersToBeginForGraphics . Submit ( RHICmdListPass , PassPipeline , Transitions ) ;
2020-09-24 00:43:27 -04:00
if ( Pass - > EpilogueBarriersToBeginForAsyncCompute )
{
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchBegin ( Pass , * Pass - > EpilogueBarriersToBeginForAsyncCompute ) ) ;
2020-11-11 19:22:36 -04:00
Pass - > EpilogueBarriersToBeginForAsyncCompute - > Submit ( RHICmdListPass , PassPipeline , Transitions ) ;
}
if ( Pass - > EpilogueBarriersToBeginForAll )
{
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchBegin ( Pass , * Pass - > EpilogueBarriersToBeginForAll ) ) ;
Pass - > EpilogueBarriersToBeginForAll - > Submit ( RHICmdListPass , PassPipeline , Transitions ) ;
}
for ( FRDGBarrierBatchBegin * BarriersToBegin : Pass - > SharedEpilogueBarriersToBegin )
{
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchBegin ( Pass , * BarriersToBegin ) ) ;
BarriersToBegin - > Submit ( RHICmdListPass , PassPipeline , Transitions ) ;
}
2021-05-19 17:54:58 -04:00
if ( ! Transitions . IsEmpty ( ) )
{
RHICmdListPass . BeginTransitions ( Transitions ) ;
}
2020-11-11 19:22:36 -04:00
if ( Pass - > EpilogueBarriersToEnd )
{
IF_RDG_ENABLE_DEBUG ( BarrierValidation . ValidateBarrierBatchEnd ( Pass , * Pass - > EpilogueBarriersToEnd ) ) ;
Pass - > EpilogueBarriersToEnd - > Submit ( RHICmdListPass , PassPipeline ) ;
2020-09-24 00:43:27 -04:00
}
IF_RDG_ENABLE_DEBUG ( UserValidation . ValidateExecutePassEnd ( Pass ) ) ;
2020-07-06 18:58:26 -04:00
}
2021-07-13 12:38:37 -04:00
void FRDGBuilder : : ExecutePass ( FRDGPass * Pass , FRHIComputeCommandList & RHICmdListPass )
2020-07-06 18:58:26 -04:00
{
2021-07-22 12:43:00 -04:00
# if RDG_EVENTS != RDG_EVENTS_NONE
SCOPED_NAMED_EVENT_TCHAR ( Pass - > GetName ( ) , FColor : : Magenta ) ;
2021-07-14 11:51:24 -04:00
# endif
2020-09-24 00:43:27 -04:00
// Note that we must do this before doing anything with RHICmdList for the pass.
// For example, if this pass only executes on GPU 1 we want to avoid adding a
// 0-duration event for this pass on GPU 0's time line.
2021-07-13 12:38:37 -04:00
SCOPED_GPU_MASK ( RHICmdListPass , Pass - > GPUMask ) ;
2020-09-24 00:43:27 -04:00
2021-07-13 12:38:37 -04:00
# if RDG_CPU_SCOPES
if ( ! Pass - > bParallelExecute )
{
Pass - > CPUScopeOps . Execute ( ) ;
}
# endif
2020-09-24 00:43:27 -04:00
2020-07-06 18:58:26 -04:00
IF_RDG_ENABLE_DEBUG ( ConditionalDebugBreak ( RDG_BREAKPOINT_PASS_EXECUTE , BuilderName . GetTCHAR ( ) , Pass - > GetName ( ) ) ) ;
# if WITH_MGPU
2021-07-13 12:38:37 -04:00
if ( Pass - > bWaitForTemporalEffect )
2020-07-06 18:58:26 -04:00
{
2021-07-13 12:38:37 -04:00
static_cast < FRHICommandList & > ( RHICmdListPass ) . WaitForTemporalEffect ( NameForTemporalEffect ) ;
2020-07-06 18:58:26 -04:00
}
# endif
ExecutePassPrologue ( RHICmdListPass , Pass ) ;
2021-02-03 14:57:28 -04:00
# if RDG_GPU_SCOPES
2021-07-13 12:38:37 -04:00
Pass - > GPUScopeOpsPrologue . Execute ( RHICmdListPass ) ;
2021-02-03 14:57:28 -04:00
# endif
2020-07-06 18:58:26 -04:00
2021-12-03 16:04:00 -05:00
# if RDG_DUMP_RESOURCES_AT_EACH_DRAW
BeginPassDump ( Pass ) ;
# endif
2021-02-03 14:57:28 -04:00
Pass - > Execute ( RHICmdListPass ) ;
2020-07-06 18:58:26 -04:00
2021-12-03 16:04:00 -05:00
# if RDG_DUMP_RESOURCES_AT_EACH_DRAW
EndPassDump ( Pass ) ;
# endif
2020-09-24 00:43:27 -04:00
# if RDG_GPU_SCOPES
2021-07-13 12:38:37 -04:00
Pass - > GPUScopeOpsEpilogue . Execute ( RHICmdListPass ) ;
2020-07-06 18:58:26 -04:00
# endif
2021-02-03 14:57:28 -04:00
ExecutePassEpilogue ( RHICmdListPass , Pass ) ;
2020-07-06 18:58:26 -04:00
if ( Pass - > bAsyncComputeEnd )
{
2021-07-13 12:38:37 -04:00
RHICmdListAsyncCompute . SetStaticUniformBuffers ( { } ) ;
2020-07-06 18:58:26 -04:00
FRHIAsyncComputeCommandListImmediate : : ImmediateDispatch ( RHICmdListAsyncCompute ) ;
}
2020-09-24 00:43:27 -04:00
2021-07-23 10:18:32 -04:00
if ( ! Pass - > bParallelExecute & & Pass - > bDispatchAfterExecute & & IsRunningRHIInSeparateThread ( ) )
{
RHICmdList . ImmediateFlush ( EImmediateFlushType : : DispatchToRHIThread ) ;
}
2021-07-13 12:38:37 -04:00
if ( ! bParallelExecuteEnabled )
2020-09-24 00:43:27 -04:00
{
2021-07-13 12:38:37 -04:00
if ( GRDGDebugFlushGPU & & ! GRDGAsyncCompute )
{
RHICmdList . SubmitCommandsAndFlushGPU ( ) ;
RHICmdList . BlockUntilGPUIdle ( ) ;
}
2021-05-19 17:54:58 -04:00
}
2018-11-21 20:22:47 -05:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : BeginResourcesRHI ( FRDGPass * ResourcePass , FRDGPassHandle ExecutePassHandle )
2019-08-15 18:58:08 -04:00
{
2021-05-19 17:54:58 -04:00
for ( FRDGPass * PassToBegin : ResourcePass - > ResourcesToBegin )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
for ( const auto & PassState : PassToBegin - > TextureStates )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
BeginResourceRHI ( ExecutePassHandle , PassState . Texture ) ;
2021-05-05 11:58:15 -04:00
}
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
for ( const auto & PassState : PassToBegin - > BufferStates )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
BeginResourceRHI ( ExecutePassHandle , PassState . Buffer ) ;
2021-05-05 11:58:15 -04:00
}
2020-11-09 13:43:23 -04:00
2021-06-01 17:25:18 -04:00
for ( FRDGUniformBufferHandle UniformBufferHandle : PassToBegin - > UniformBuffers )
{
if ( FRDGUniformBuffer * UniformBuffer = UniformBuffers [ UniformBufferHandle ] ; ! UniformBuffer - > bQueuedForCreate )
{
UniformBuffer - > bQueuedForCreate = true ;
UniformBuffersToCreate . Add ( UniformBufferHandle ) ;
}
}
2021-05-05 11:58:15 -04:00
for ( FRDGViewHandle ViewHandle : PassToBegin - > Views )
2020-11-09 13:43:23 -04:00
{
2022-04-22 17:11:57 -04:00
InitRHI ( Views [ ViewHandle ] ) ;
2020-09-24 00:43:27 -04:00
}
}
}
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : EndResourcesRHI ( FRDGPass * ResourcePass , FRDGPassHandle ExecutePassHandle )
2020-09-24 00:43:27 -04:00
{
2021-05-19 17:54:58 -04:00
for ( FRDGPass * PassToEnd : ResourcePass - > ResourcesToEnd )
2020-07-06 18:58:26 -04:00
{
2021-05-19 17:54:58 -04:00
for ( const auto & PassState : PassToEnd - > TextureStates )
{
EndResourceRHI ( ExecutePassHandle , PassState . Texture , PassState . ReferenceCount ) ;
}
for ( const auto & PassState : PassToEnd - > BufferStates )
{
EndResourceRHI ( ExecutePassHandle , PassState . Buffer , PassState . ReferenceCount ) ;
}
2020-09-24 00:43:27 -04:00
}
2021-05-19 17:54:58 -04:00
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : CollectPassBarriers ( FRDGPass * Pass , FRDGPassHandle PassHandle )
{
IF_RDG_ENABLE_DEBUG ( ConditionalDebugBreak ( RDG_BREAKPOINT_PASS_COMPILE , BuilderName . GetTCHAR ( ) , Pass - > GetName ( ) ) ) ;
2020-09-24 00:43:27 -04:00
2021-05-05 11:58:15 -04:00
for ( const auto & PassState : Pass - > TextureStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGTextureRef Texture = PassState . Texture ;
AddTransition ( PassHandle , Texture , PassState . MergeState ) ;
2021-02-03 13:17:04 -04:00
2021-02-05 12:11:16 -04:00
IF_RDG_ENABLE_TRACE ( Trace . AddTexturePassDependency ( Texture , Pass ) ) ;
2020-09-24 00:43:27 -04:00
}
2021-05-05 11:58:15 -04:00
for ( const auto & PassState : Pass - > BufferStates )
2020-09-24 00:43:27 -04:00
{
2021-05-05 11:58:15 -04:00
FRDGBufferRef Buffer = PassState . Buffer ;
AddTransition ( PassHandle , Buffer , * PassState . MergeState ) ;
2021-02-03 13:17:04 -04:00
2021-02-05 12:11:16 -04:00
IF_RDG_ENABLE_TRACE ( Trace . AddBufferPassDependency ( Buffer , Pass ) ) ;
2020-09-24 00:43:27 -04:00
}
}
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : CreatePassBarriers ( )
{
2021-07-22 12:43:00 -04:00
SCOPED_NAMED_EVENT_TEXT ( " FRDGBuilder::CreatePassBarriers " , FColor : : Magenta ) ;
2021-05-19 17:54:58 -04:00
for ( FRDGBarrierBatchBegin * BarrierBatchBegin : TransitionCreateQueue )
{
BarrierBatchBegin - > CreateTransition ( ) ;
}
TransitionCreateQueue . Reset ( ) ;
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-02-18 20:06:45 -04:00
void FRDGBuilder : : AddEpilogueTransition ( FRDGTextureRef Texture )
2020-09-24 00:43:27 -04:00
{
2022-04-25 13:00:12 -04:00
if ( ! Texture - > HasRHI ( ) | | Texture - > bCulled | | ! Texture - > bLastOwner )
2020-09-24 00:43:27 -04:00
{
return ;
}
2022-05-02 18:31:37 -04:00
if ( ! EnumHasAnyFlags ( Texture - > Flags , ERDGTextureFlags : : SkipTracking ) )
2021-03-17 12:44:59 -04:00
{
2022-03-25 11:19:10 -04:00
const FRDGPassHandle EpiloguePassHandle = GetEpiloguePassHandle ( ) ;
2021-08-16 17:32:38 -04:00
2022-03-25 11:19:10 -04:00
FRDGSubresourceState SubresourceState ;
SubresourceState . SetPass ( ERHIPipeline : : Graphics , EpiloguePassHandle ) ;
2021-08-16 17:32:38 -04:00
2022-03-25 11:19:10 -04:00
// Texture is using the RHI transient allocator. Transition it back to Discard in the final pass it is used.
if ( Texture - > bTransient & & ! Texture - > TransientTexture - > IsAcquired ( ) )
2020-07-06 18:58:26 -04:00
{
2022-03-25 11:19:10 -04:00
const TInterval < uint32 > DiscardPasses = Texture - > TransientTexture - > GetDiscardPasses ( ) ;
const FRDGPassHandle MinDiscardPassHandle ( DiscardPasses . Min ) ;
const FRDGPassHandle MaxDiscardPassHandle ( FMath : : Min < uint32 > ( DiscardPasses . Max , EpiloguePassHandle . GetIndex ( ) ) ) ;
2020-07-06 18:58:26 -04:00
2022-03-25 11:19:10 -04:00
AddAliasingTransition ( MinDiscardPassHandle , MaxDiscardPassHandle , Texture , FRHITransientAliasingInfo : : Discard ( Texture - > GetRHIUnchecked ( ) ) ) ;
2020-07-06 18:58:26 -04:00
2022-03-25 11:19:10 -04:00
SubresourceState . SetPass ( ERHIPipeline : : Graphics , MaxDiscardPassHandle ) ;
Texture - > EpilogueAccess = ERHIAccess : : Discard ;
2020-07-06 18:58:26 -04:00
}
2022-03-25 11:19:10 -04:00
SubresourceState . Access = Texture - > EpilogueAccess ;
InitAsWholeResource ( ScratchTextureState , & SubresourceState ) ;
AddTransition ( EpiloguePassHandle , Texture , ScratchTextureState ) ;
ScratchTextureState . Reset ( ) ;
2020-09-24 00:43:27 -04:00
2022-03-25 11:19:10 -04:00
EpilogueResourceAccesses . Emplace ( Texture - > GetRHI ( ) , Texture - > EpilogueAccess ) ;
}
2022-04-05 13:14:19 -04:00
if ( Texture - > Allocation )
2022-03-25 11:19:10 -04:00
{
2022-04-05 13:14:19 -04:00
ActivePooledTextures . Emplace ( MoveTemp ( Texture - > Allocation ) ) ;
}
else if ( ! Texture - > bTransient )
{
2022-04-25 13:00:12 -04:00
// Non-transient textures need to be 'resurrected' to hold the last reference in the chain.
// Transient textures don't have that restriction since there's no actual pooling happening.
2022-03-25 11:19:10 -04:00
ActivePooledTextures . Emplace ( Texture - > RenderTarget ) ;
}
2020-09-24 00:43:27 -04:00
}
2021-02-18 20:06:45 -04:00
void FRDGBuilder : : AddEpilogueTransition ( FRDGBufferRef Buffer )
2020-09-24 00:43:27 -04:00
{
2022-04-25 13:00:12 -04:00
if ( ! Buffer - > HasRHI ( ) | | Buffer - > bCulled | | ! Buffer - > bLastOwner )
2020-09-24 00:43:27 -04:00
{
return ;
}
2022-05-02 18:31:37 -04:00
if ( ! EnumHasAnyFlags ( Buffer - > Flags , ERDGBufferFlags : : SkipTracking ) )
2020-09-24 00:43:27 -04:00
{
2022-03-25 11:19:10 -04:00
const FRDGPassHandle EpiloguePassHandle = GetEpiloguePassHandle ( ) ;
2021-08-16 17:32:38 -04:00
2022-03-25 11:19:10 -04:00
FRDGSubresourceState SubresourceState ;
SubresourceState . SetPass ( ERHIPipeline : : Graphics , EpiloguePassHandle ) ;
2021-08-16 17:32:38 -04:00
2022-03-25 11:19:10 -04:00
// Texture is using the RHI transient allocator. Transition it back to Discard in the final pass it is used.
if ( Buffer - > bTransient )
{
const TInterval < uint32 > DiscardPasses = Buffer - > TransientBuffer - > GetDiscardPasses ( ) ;
const FRDGPassHandle MinDiscardPassHandle ( DiscardPasses . Min ) ;
const FRDGPassHandle MaxDiscardPassHandle ( FMath : : Min < uint32 > ( DiscardPasses . Max , EpiloguePassHandle . GetIndex ( ) ) ) ;
AddAliasingTransition ( MinDiscardPassHandle , MaxDiscardPassHandle , Buffer , FRHITransientAliasingInfo : : Discard ( Buffer - > GetRHIUnchecked ( ) ) ) ;
SubresourceState . SetPass ( ERHIPipeline : : Graphics , MaxDiscardPassHandle ) ;
Buffer - > EpilogueAccess = ERHIAccess : : Discard ;
}
SubresourceState . Access = Buffer - > EpilogueAccess ;
AddTransition ( Buffer - > LastPass , Buffer , SubresourceState ) ;
EpilogueResourceAccesses . Emplace ( Buffer - > GetRHI ( ) , Buffer - > EpilogueAccess ) ;
}
2022-04-22 17:11:57 -04:00
if ( Buffer - > Allocation )
2022-03-25 11:19:10 -04:00
{
2022-04-22 17:11:57 -04:00
ActivePooledBuffers . Emplace ( MoveTemp ( Buffer - > Allocation ) ) ;
}
else if ( ! Buffer - > bTransient )
{
// Non-transient buffers need to be 'resurrected' to hold the last reference in the chain.
// Transient buffers don't have that restriction since there's no actual pooling happening.
2022-03-25 11:19:10 -04:00
ActivePooledBuffers . Emplace ( Buffer - > PooledBuffer ) ;
}
2020-07-06 18:58:26 -04:00
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2022-03-25 11:19:10 -04:00
void FRDGBuilder : : AddTransition ( FRDGPassHandle PassHandle , FRDGTextureRef Texture , const FRDGTextureSubresourceStateIndirect & StateAfter )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
const FRDGTextureSubresourceRange WholeRange = Texture - > GetSubresourceRange ( ) ;
const FRDGTextureSubresourceLayout Layout = Texture - > Layout ;
FRDGTextureSubresourceState & StateBefore = Texture - > GetState ( ) ;
2019-06-11 18:27:07 -04:00
2022-05-04 17:36:33 -04:00
// Use the entire texture for copy states on RHI's that don't track them separately
if ( ! GRHISupportsSeparateDepthStencilCopyAccess )
{
if ( ( Texture - > Desc . Format = = PF_DepthStencil ) & & ! IsWholeResource ( StateAfter ) )
{
const ERHIAccess AnyCopyAccess = ERHIAccess : : CopySrc | ERHIAccess : : CopyDest ;
uint32 TotalTransitionCount = 0 ;
uint32 CopyTransitionCount = 0 ;
WholeRange . EnumerateSubresources ( [ & ] ( FRDGTextureSubresource Subresource )
{
if ( FRDGSubresourceState * SubresourceStateAfter = GetSubresource ( StateAfter , Layout , Subresource ) )
{
+ + TotalTransitionCount ;
if ( EnumHasAnyFlags ( SubresourceStateAfter - > Access , AnyCopyAccess ) )
{
+ + CopyTransitionCount ;
}
}
} ) ;
// Use a common FRDGSubresourceState to keep the transitions of depth/stencil together in the same pass
if ( ( CopyTransitionCount > 0 ) & & ! IsWholeResource ( StateBefore ) )
{
checkf ( ( CopyTransitionCount = = TotalTransitionCount ) , TEXT ( " Depth/Stencil Copy transitions on this platform are supposed to touch all subresources. " ) ) ;
const FRDGTextureSubresource MaxSubresource = WholeRange . GetMaxSubresource ( ) ;
const FRDGTextureSubresource MinSubresource = WholeRange . GetMinSubresource ( ) ;
for ( uint32 LocalArraySlice = MinSubresource . ArraySlice ; LocalArraySlice < MaxSubresource . ArraySlice ; + + LocalArraySlice )
{
for ( uint32 LocalMipIndex = MinSubresource . MipIndex ; LocalMipIndex < MaxSubresource . MipIndex ; + + LocalMipIndex )
{
FRDGSubresourceState * LatestSubresourceStateBefore = nullptr ;
for ( uint32 LocalPlaneSlice = MinSubresource . PlaneSlice ; LocalPlaneSlice < MaxSubresource . PlaneSlice ; + + LocalPlaneSlice )
{
FRDGSubresourceState & OtherStateBefore = GetSubresource ( StateBefore , Layout , FRDGTextureSubresource ( LocalMipIndex , LocalArraySlice , LocalPlaneSlice ) ) ;
if ( LatestSubresourceStateBefore = = nullptr )
{
LatestSubresourceStateBefore = & OtherStateBefore ;
}
else if ( LatestSubresourceStateBefore - > GetLastPass ( ) < OtherStateBefore . GetLastPass ( ) )
{
* LatestSubresourceStateBefore = OtherStateBefore ;
}
else if ( LatestSubresourceStateBefore - > GetLastPass ( ) > OtherStateBefore . GetLastPass ( ) )
{
OtherStateBefore = * LatestSubresourceStateBefore ;
}
}
}
}
}
}
}
2020-09-24 00:43:27 -04:00
const auto AddSubresourceTransition = [ & ] (
const FRDGSubresourceState & SubresourceStateBefore ,
const FRDGSubresourceState & SubresourceStateAfter ,
FRDGTextureSubresource * Subresource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
check ( SubresourceStateAfter . Access ! = ERHIAccess : : Unknown ) ;
2020-07-06 18:58:26 -04:00
2020-09-24 00:43:27 -04:00
if ( FRDGSubresourceState : : IsTransitionRequired ( SubresourceStateBefore , SubresourceStateAfter ) )
{
FRHITransitionInfo Info ;
Info . Texture = Texture - > GetRHIUnchecked ( ) ;
Info . Type = FRHITransitionInfo : : EType : : Texture ;
Info . Flags = SubresourceStateAfter . Flags ;
Info . AccessBefore = SubresourceStateBefore . Access ;
Info . AccessAfter = SubresourceStateAfter . Access ;
2021-04-06 13:11:13 -04:00
if ( Info . AccessBefore = = ERHIAccess : : Discard )
{
Info . Flags | = EResourceTransitionFlags : : Discard ;
}
2020-09-24 00:43:27 -04:00
if ( Subresource )
{
Info . MipIndex = Subresource - > MipIndex ;
Info . ArraySlice = Subresource - > ArraySlice ;
Info . PlaneSlice = Subresource - > PlaneSlice ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
2021-08-16 17:32:38 -04:00
AddTransition ( Texture , SubresourceStateBefore , SubresourceStateAfter , Info ) ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
} ;
2020-09-24 00:43:27 -04:00
if ( IsWholeResource ( StateBefore ) )
{
// 1 -> 1
if ( IsWholeResource ( StateAfter ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( const FRDGSubresourceState * SubresourceStateAfter = GetWholeResource ( StateAfter ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGSubresourceState & SubresourceStateBefore = GetWholeResource ( StateBefore ) ;
AddSubresourceTransition ( SubresourceStateBefore , * SubresourceStateAfter , nullptr ) ;
2021-05-25 17:11:34 -04:00
SubresourceStateBefore = * SubresourceStateAfter ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
2020-09-24 00:43:27 -04:00
// 1 -> N
2020-07-06 18:58:26 -04:00
else
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
const FRDGSubresourceState SubresourceStateBeforeWhole = GetWholeResource ( StateBefore ) ;
InitAsSubresources ( StateBefore , Layout , SubresourceStateBeforeWhole ) ;
WholeRange . EnumerateSubresources ( [ & ] ( FRDGTextureSubresource Subresource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( FRDGSubresourceState * SubresourceStateAfter = GetSubresource ( StateAfter , Layout , Subresource ) )
{
AddSubresourceTransition ( SubresourceStateBeforeWhole , * SubresourceStateAfter , & Subresource ) ;
FRDGSubresourceState & SubresourceStateBefore = GetSubresource ( StateBefore , Layout , Subresource ) ;
2021-05-25 17:11:34 -04:00
SubresourceStateBefore = * SubresourceStateAfter ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
2019-06-11 18:27:07 -04:00
}
}
2020-07-06 18:58:26 -04:00
else
2019-06-11 18:27:07 -04:00
{
2020-09-24 00:43:27 -04:00
// N -> 1
if ( IsWholeResource ( StateAfter ) )
2019-06-11 18:27:07 -04:00
{
2020-09-24 00:43:27 -04:00
if ( const FRDGSubresourceState * SubresourceStateAfter = GetWholeResource ( StateAfter ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
WholeRange . EnumerateSubresources ( [ & ] ( FRDGTextureSubresource Subresource )
{
AddSubresourceTransition ( GetSubresource ( StateBefore , Layout , Subresource ) , * SubresourceStateAfter , & Subresource ) ;
} ) ;
InitAsWholeResource ( StateBefore ) ;
FRDGSubresourceState & SubresourceStateBefore = GetWholeResource ( StateBefore ) ;
2021-05-25 17:11:34 -04:00
SubresourceStateBefore = * SubresourceStateAfter ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
// N -> N
2020-07-06 18:58:26 -04:00
else
{
2020-09-24 00:43:27 -04:00
WholeRange . EnumerateSubresources ( [ & ] ( FRDGTextureSubresource Subresource )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
if ( FRDGSubresourceState * SubresourceStateAfter = GetSubresource ( StateAfter , Layout , Subresource ) )
{
FRDGSubresourceState & SubresourceStateBefore = GetSubresource ( StateBefore , Layout , Subresource ) ;
AddSubresourceTransition ( SubresourceStateBefore , * SubresourceStateAfter , & Subresource ) ;
2021-05-25 17:11:34 -04:00
SubresourceStateBefore = * SubresourceStateAfter ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
}
2021-08-16 17:32:38 -04:00
void FRDGBuilder : : AddTransition ( FRDGPassHandle PassHandle , FRDGBufferRef Buffer , FRDGSubresourceState StateAfter )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
check ( StateAfter . Access ! = ERHIAccess : : Unknown ) ;
FRDGSubresourceState & StateBefore = Buffer - > GetState ( ) ;
if ( FRDGSubresourceState : : IsTransitionRequired ( StateBefore , StateAfter ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRHITransitionInfo Info ;
Info . Resource = Buffer - > GetRHIUnchecked ( ) ;
2020-11-30 13:27:08 -04:00
Info . Type = FRHITransitionInfo : : EType : : Buffer ;
2020-09-24 00:43:27 -04:00
Info . Flags = StateAfter . Flags ;
Info . AccessBefore = StateBefore . Access ;
Info . AccessAfter = StateAfter . Access ;
2020-07-06 18:58:26 -04:00
2021-08-16 17:32:38 -04:00
AddTransition ( Buffer , StateBefore , StateAfter , Info ) ;
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
StateBefore = StateAfter ;
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
void FRDGBuilder : : AddTransition (
2022-03-25 11:19:10 -04:00
FRDGViewableResource * Resource ,
2020-07-06 18:58:26 -04:00
FRDGSubresourceState StateBefore ,
FRDGSubresourceState StateAfter ,
2021-08-16 17:32:38 -04:00
const FRHITransitionInfo & TransitionInfo )
2020-07-06 18:58:26 -04:00
{
2020-11-11 19:22:36 -04:00
const ERHIPipeline Graphics = ERHIPipeline : : Graphics ;
const ERHIPipeline AsyncCompute = ERHIPipeline : : AsyncCompute ;
2020-09-24 00:43:27 -04:00
2020-11-11 19:22:36 -04:00
# if RDG_ENABLE_DEBUG
StateBefore . Validate ( ) ;
StateAfter . Validate ( ) ;
# endif
2021-03-17 12:44:59 -04:00
if ( IsImmediateMode ( ) )
2020-07-06 18:58:26 -04:00
{
2021-03-17 12:44:59 -04:00
// Immediate mode simply enqueues the barrier into the 'after' pass. Everything is on the graphics pipe.
2021-08-16 17:32:38 -04:00
AddToPrologueBarriers ( StateAfter . FirstPass [ Graphics ] , [ & ] ( FRDGBarrierBatchBegin & Barriers )
2021-03-17 12:44:59 -04:00
{
Barriers . AddTransition ( Resource , TransitionInfo ) ;
} ) ;
2020-11-11 19:22:36 -04:00
return ;
2020-07-06 18:58:26 -04:00
}
2020-11-11 19:22:36 -04:00
ERHIPipeline PipelinesBefore = StateBefore . GetPipelines ( ) ;
ERHIPipeline PipelinesAfter = StateAfter . GetPipelines ( ) ;
// This may be the first use of the resource in the graph, so we assign the prologue as the previous pass.
if ( PipelinesBefore = = ERHIPipeline : : None )
{
StateBefore . SetPass ( Graphics , GetProloguePassHandle ( ) ) ;
PipelinesBefore = Graphics ;
}
check ( PipelinesBefore ! = ERHIPipeline : : None & & PipelinesAfter ! = ERHIPipeline : : None ) ;
2021-03-17 12:44:59 -04:00
checkf ( StateBefore . GetLastPass ( ) < = StateAfter . GetFirstPass ( ) , TEXT ( " Submitted a state for '%s' that begins before our previous state has ended. " ) , Resource - > Name ) ;
2020-11-11 19:22:36 -04:00
2021-05-19 17:54:58 -04:00
const FRDGPassHandlesByPipeline & PassesBefore = StateBefore . LastPass ;
const FRDGPassHandlesByPipeline & PassesAfter = StateAfter . FirstPass ;
2020-11-11 19:22:36 -04:00
// 1-to-1 or 1-to-N pipe transition.
2021-05-19 17:54:58 -04:00
if ( PipelinesBefore ! = ERHIPipeline : : All )
2020-11-11 19:22:36 -04:00
{
const FRDGPassHandle BeginPassHandle = StateBefore . GetLastPass ( ) ;
const FRDGPassHandle FirstEndPassHandle = StateAfter . GetFirstPass ( ) ;
FRDGPass * BeginPass = nullptr ;
FRDGBarrierBatchBegin * BarriersToBegin = nullptr ;
2021-03-17 12:44:59 -04:00
// Issue the begin in the epilogue of the begin pass if the barrier is being split across multiple passes or the barrier end is in the epilogue.
2021-08-16 17:32:38 -04:00
if ( BeginPassHandle < FirstEndPassHandle )
2020-11-11 19:22:36 -04:00
{
BeginPass = GetEpilogueBarrierPass ( BeginPassHandle ) ;
2021-05-19 17:54:58 -04:00
BarriersToBegin = & BeginPass - > GetEpilogueBarriersToBeginFor ( Allocator , TransitionCreateQueue , PipelinesAfter ) ;
2020-11-11 19:22:36 -04:00
}
2021-03-17 12:44:59 -04:00
// This is an immediate prologue transition in the same pass. Issue the begin in the prologue.
2020-11-11 19:22:36 -04:00
else
{
2021-03-17 12:44:59 -04:00
checkf ( PipelinesAfter = = ERHIPipeline : : Graphics ,
TEXT ( " Attempted to queue an immediate async pipe transition for %s. Pipelines: %s. Async transitions must be split. " ) ,
Resource - > Name , * GetRHIPipelineName ( PipelinesAfter ) ) ;
2020-11-11 19:22:36 -04:00
BeginPass = GetPrologueBarrierPass ( BeginPassHandle ) ;
2021-05-19 17:54:58 -04:00
BarriersToBegin = & BeginPass - > GetPrologueBarriersToBegin ( Allocator , TransitionCreateQueue ) ;
2020-11-11 19:22:36 -04:00
}
BarriersToBegin - > AddTransition ( Resource , TransitionInfo ) ;
for ( ERHIPipeline Pipeline : GetRHIPipelines ( ) )
{
2021-03-17 12:44:59 -04:00
/** If doing a 1-to-N transition and this is the same pipe as the begin, we end it immediately afterwards in the epilogue
* of the begin pass . This is because we can ' t guarantee that the other pipeline won ' t join back before the end . This can
* happen if the forking async compute pass joins back to graphics ( via another independent transition ) before the current
* graphics transition is ended .
*
* Async Compute Pipe : EndA BeginB
* / \
* Graphics Pipe : BeginA EndB EndA
*
* A is our 1 - to - N transition and B is a future transition of the same resource that we haven ' t evaluated yet . Instead , the
* same pipe End is performed in the epilogue of the begin pass , which removes the spit barrier but simplifies the tracking :
*
* Async Compute Pipe : EndA BeginB
* / \
* Graphics Pipe : BeginA EndA EndB
*/
2021-05-19 17:54:58 -04:00
if ( ( PipelinesBefore = = Pipeline & & PipelinesAfter = = ERHIPipeline : : All ) )
2020-11-11 19:22:36 -04:00
{
2021-03-17 12:44:59 -04:00
AddToEpilogueBarriersToEnd ( BeginPassHandle , * BarriersToBegin ) ;
2020-11-11 19:22:36 -04:00
}
else if ( EnumHasAnyFlags ( PipelinesAfter , Pipeline ) )
{
2021-08-16 17:32:38 -04:00
AddToPrologueBarriersToEnd ( PassesAfter [ Pipeline ] , * BarriersToBegin ) ;
2020-11-11 19:22:36 -04:00
}
}
2020-07-06 18:58:26 -04:00
}
2021-04-04 21:16:04 -04:00
// N-to-1 or N-to-N transition.
2020-07-06 18:58:26 -04:00
else
{
2021-08-16 17:32:38 -04:00
checkf ( StateBefore . GetLastPass ( ) ! = StateAfter . GetFirstPass ( ) ,
2020-11-11 19:22:36 -04:00
TEXT ( " Attempted to queue a transition for resource '%s' from '%s' to '%s', but previous and next passes are the same on one pipe. " ) ,
Resource - > Name , * GetRHIPipelineName ( PipelinesBefore ) , * GetRHIPipelineName ( PipelinesAfter ) ) ;
2020-07-06 18:58:26 -04:00
2020-11-11 19:22:36 -04:00
FRDGBarrierBatchBeginId Id ;
Id . PipelinesAfter = PipelinesAfter ;
for ( ERHIPipeline Pipeline : GetRHIPipelines ( ) )
{
Id . Passes [ Pipeline ] = GetEpilogueBarrierPassHandle ( PassesBefore [ Pipeline ] ) ;
}
FRDGBarrierBatchBegin * & BarriersToBegin = BarrierBatchMap . FindOrAdd ( Id ) ;
if ( ! BarriersToBegin )
{
2021-05-19 17:54:58 -04:00
FRDGPassesByPipeline BarrierBatchPasses ;
BarrierBatchPasses [ Graphics ] = Passes [ Id . Passes [ Graphics ] ] ;
BarrierBatchPasses [ AsyncCompute ] = Passes [ Id . Passes [ AsyncCompute ] ] ;
2020-11-11 19:22:36 -04:00
2021-05-19 17:54:58 -04:00
BarriersToBegin = Allocator . AllocNoDestruct < FRDGBarrierBatchBegin > ( PipelinesBefore , PipelinesAfter , GetEpilogueBarriersToBeginDebugName ( PipelinesAfter ) , BarrierBatchPasses ) ;
TransitionCreateQueue . Emplace ( BarriersToBegin ) ;
for ( FRDGPass * Pass : BarrierBatchPasses )
2020-11-11 19:22:36 -04:00
{
2021-05-19 17:54:58 -04:00
Pass - > SharedEpilogueBarriersToBegin . Add ( BarriersToBegin ) ;
2020-11-11 19:22:36 -04:00
}
}
BarriersToBegin - > AddTransition ( Resource , TransitionInfo ) ;
for ( ERHIPipeline Pipeline : GetRHIPipelines ( ) )
{
if ( EnumHasAnyFlags ( PipelinesAfter , Pipeline ) )
{
2021-08-16 17:32:38 -04:00
AddToPrologueBarriersToEnd ( PassesAfter [ Pipeline ] , * BarriersToBegin ) ;
2020-11-11 19:22:36 -04:00
}
}
}
2020-07-06 18:58:26 -04:00
}
2022-03-25 11:19:10 -04:00
void FRDGBuilder : : AddAliasingTransition ( FRDGPassHandle BeginPassHandle , FRDGPassHandle EndPassHandle , FRDGViewableResource * Resource , const FRHITransientAliasingInfo & Info )
2021-08-16 17:32:38 -04:00
{
check ( BeginPassHandle < = EndPassHandle ) ;
FRDGBarrierBatchBegin * BarriersToBegin { } ;
FRDGPass * EndPass { } ;
if ( BeginPassHandle = = EndPassHandle )
{
FRDGPass * BeginPass = Passes [ BeginPassHandle ] ;
EndPass = BeginPass ;
check ( GetPrologueBarrierPassHandle ( BeginPassHandle ) = = BeginPassHandle ) ;
check ( BeginPass - > GetPipeline ( ) = = ERHIPipeline : : Graphics ) ;
BarriersToBegin = & BeginPass - > GetPrologueBarriersToBegin ( Allocator , TransitionCreateQueue ) ;
}
else
{
FRDGPass * BeginPass = GetEpilogueBarrierPass ( BeginPassHandle ) ;
EndPass = Passes [ EndPassHandle ] ;
check ( GetPrologueBarrierPassHandle ( EndPassHandle ) = = EndPassHandle ) ;
check ( BeginPass - > GetPipeline ( ) = = ERHIPipeline : : Graphics ) ;
check ( EndPass - > GetPipeline ( ) = = ERHIPipeline : : Graphics ) ;
BarriersToBegin = & BeginPass - > GetEpilogueBarriersToBeginForGraphics ( Allocator , TransitionCreateQueue ) ;
}
BarriersToBegin - > AddAlias ( Resource , Info ) ;
EndPass - > GetPrologueBarriersToEnd ( Allocator ) . AddDependency ( BarriersToBegin ) ;
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
void FRDGBuilder : : SetRHI ( FRDGTexture * Texture , IPooledRenderTarget * RenderTarget , FRDGPassHandle PassHandle )
{
Texture - > RenderTarget = RenderTarget ;
if ( FRHITransientTexture * TransientTexture = RenderTarget - > GetTransientTexture ( ) )
{
FRDGTransientRenderTarget * TransientRenderTarget = static_cast < FRDGTransientRenderTarget * > ( RenderTarget ) ;
Texture - > Allocation = TRefCountPtr < FRDGTransientRenderTarget > ( TransientRenderTarget ) ;
SetRHI ( Texture , TransientTexture , PassHandle ) ;
}
else
{
FPooledRenderTarget * PooledRenderTarget = static_cast < FPooledRenderTarget * > ( RenderTarget ) ;
Texture - > Allocation = TRefCountPtr < FPooledRenderTarget > ( PooledRenderTarget ) ;
SetRHI ( Texture , & PooledRenderTarget - > PooledTexture , PassHandle ) ;
}
}
void FRDGBuilder : : SetRHI ( FRDGTexture * Texture , FRDGPooledTexture * PooledTexture , FRDGPassHandle PassHandle )
{
FRHITexture * TextureRHI = PooledTexture - > GetRHI ( ) ;
Texture - > ResourceRHI = TextureRHI ;
Texture - > PooledTexture = PooledTexture ;
Texture - > ViewCache = & PooledTexture - > ViewCache ;
Texture - > FirstPass = PassHandle ;
FRDGTexture * & Owner = PooledTextureOwnershipMap . FindOrAdd ( PooledTexture ) ;
// Link the previous alias to this one.
if ( Owner )
{
Owner - > NextOwner = Texture - > Handle ;
Owner - > bLastOwner = false ;
// Chain the state allocation between all RDG textures which share this pooled texture.
Texture - > State = Owner - > State ;
}
else
{
Texture - > State = Allocator . AllocNoDestruct < FRDGTextureSubresourceState > ( ) ;
InitAsWholeResource ( * Texture - > State , { } ) ;
}
Owner = Texture ;
}
void FRDGBuilder : : SetRHI ( FRDGTexture * Texture , FRHITransientTexture * TransientTexture , FRDGPassHandle PassHandle )
{
Texture - > ResourceRHI = TransientTexture - > GetRHI ( ) ;
Texture - > TransientTexture = TransientTexture ;
Texture - > ViewCache = & TransientTexture - > ViewCache ;
Texture - > FirstPass = PassHandle ;
Texture - > bTransient = true ;
Texture - > State = Allocator . AllocNoDestruct < FRDGTextureSubresourceState > ( ) ;
2022-04-01 13:05:11 -04:00
InitAsWholeResource ( * Texture - > State , { } ) ;
2022-03-25 11:19:10 -04:00
}
void FRDGBuilder : : SetRHI ( FRDGBuffer * Buffer , FRDGPooledBuffer * PooledBuffer , FRDGPassHandle PassHandle )
{
FRHIBuffer * BufferRHI = PooledBuffer - > GetRHI ( ) ;
Buffer - > ResourceRHI = BufferRHI ;
Buffer - > PooledBuffer = PooledBuffer ;
Buffer - > ViewCache = & PooledBuffer - > ViewCache ;
Buffer - > Allocation = PooledBuffer ;
Buffer - > FirstPass = PassHandle ;
FRDGBuffer * & Owner = PooledBufferOwnershipMap . FindOrAdd ( PooledBuffer ) ;
// Link the previous owner to this one.
if ( Owner )
{
Owner - > NextOwner = Buffer - > Handle ;
Owner - > bLastOwner = false ;
// Chain the state allocation between all RDG buffers which share this pooled buffer.
Buffer - > State = Owner - > State ;
}
else
{
Buffer - > State = Allocator . AllocNoDestruct < FRDGSubresourceState > ( ) ;
}
Owner = Buffer ;
}
void FRDGBuilder : : SetRHI ( FRDGBuffer * Buffer , FRHITransientBuffer * TransientBuffer , FRDGPassHandle PassHandle )
{
check ( ! Buffer - > ResourceRHI ) ;
Buffer - > ResourceRHI = TransientBuffer - > GetRHI ( ) ;
Buffer - > TransientBuffer = TransientBuffer ;
Buffer - > ViewCache = & TransientBuffer - > ViewCache ;
Buffer - > FirstPass = PassHandle ;
Buffer - > bTransient = true ;
2022-04-01 13:05:11 -04:00
Buffer - > State = Allocator . AllocNoDestruct < FRDGSubresourceState > ( ) ;
2022-03-25 11:19:10 -04:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : BeginResourceRHI ( FRDGPassHandle PassHandle , FRDGTextureRef Texture )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
check ( Texture ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
if ( Texture - > HasRHI ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
return ;
}
2021-03-17 12:44:59 -04:00
check ( Texture - > ReferenceCount > 0 | | Texture - > bExternal | | IsImmediateMode ( ) ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-09-24 00:43:27 -04:00
# if RDG_ENABLE_DEBUG
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
FRDGPass * Pass = Passes [ PassHandle ] ;
2021-05-25 17:11:34 -04:00
// Cannot begin a resource on an async compute pass.
check ( Pass - > Pipeline = = ERHIPipeline : : Graphics ) ;
// Cannot begin a resource within a merged render pass region.
2022-01-20 16:30:26 -05:00
checkf ( GetPrologueBarrierPassHandle ( PassHandle ) = = PassHandle ,
TEXT ( " Cannot begin a resource within a merged render pass. Pass (Handle: %d, Name: %s), Resource %s " ) , PassHandle , Pass - > GetName ( ) , Texture - > Name ) ;
2020-09-24 00:43:27 -04:00
}
# endif
2020-07-06 18:58:26 -04:00
2022-01-03 18:28:16 -05:00
if ( TransientResourceAllocator & & IsTransient ( Texture ) )
2020-09-24 00:43:27 -04:00
{
2022-01-03 18:28:16 -05:00
if ( FRHITransientTexture * TransientTexture = TransientResourceAllocator - > CreateTexture ( Texture - > Desc , Texture - > Name , PassHandle . GetIndex ( ) ) )
2020-09-24 00:43:27 -04:00
{
2022-01-03 18:28:16 -05:00
if ( Texture - > bExternal | | Texture - > bExtracted )
2021-03-17 12:44:59 -04:00
{
2022-03-25 11:19:10 -04:00
SetRHI ( Texture , GRDGTransientResourceAllocator . AllocateRenderTarget ( TransientTexture ) , PassHandle ) ;
2021-04-21 13:03:28 -04:00
}
2022-01-03 18:28:16 -05:00
else
{
2022-03-25 11:19:10 -04:00
SetRHI ( Texture , TransientTexture , PassHandle ) ;
2022-01-03 18:28:16 -05:00
}
2022-04-01 13:05:11 -04:00
const FRDGPassHandle MinAcquirePassHandle ( TransientTexture - > GetAcquirePasses ( ) . Min ) ;
AddAliasingTransition ( MinAcquirePassHandle , PassHandle , Texture , FRHITransientAliasingInfo : : Acquire ( TransientTexture - > GetRHI ( ) , TransientTexture - > GetAliasingOverlaps ( ) ) ) ;
FRDGSubresourceState InitialState ;
InitialState . SetPass ( ERHIPipeline : : Graphics , MinAcquirePassHandle ) ;
InitialState . Access = ERHIAccess : : Discard ;
InitAsWholeResource ( * Texture - > State , InitialState ) ;
2022-01-03 18:28:16 -05:00
# if STATS
GRDGStatTransientTextureCount + + ;
# endif
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
}
2021-03-17 12:44:59 -04:00
2022-01-03 18:28:16 -05:00
if ( ! Texture - > ResourceRHI )
2021-03-17 12:44:59 -04:00
{
2022-03-25 11:19:10 -04:00
SetRHI ( Texture , GRenderTargetPool . FindFreeElement ( Texture - > Desc , Texture - > Name ) , PassHandle ) ;
2021-03-17 12:44:59 -04:00
}
2018-10-22 23:01:29 -04:00
}
2022-04-22 17:11:57 -04:00
void FRDGBuilder : : InitRHI ( FRDGTextureSRVRef SRV )
2019-07-18 19:08:07 -04:00
{
check ( SRV ) ;
2021-05-19 17:54:58 -04:00
if ( SRV - > HasRHI ( ) )
2019-07-18 19:08:07 -04:00
{
return ;
}
FRDGTextureRef Texture = SRV - > Desc . Texture ;
2021-04-26 14:12:08 -04:00
FRHITexture * TextureRHI = Texture - > GetRHIUnchecked ( ) ;
check ( TextureRHI ) ;
2020-09-24 00:43:27 -04:00
2021-04-26 14:12:08 -04:00
SRV - > ResourceRHI = Texture - > ViewCache - > GetOrCreateSRV ( TextureRHI , SRV - > Desc ) ;
2019-07-18 19:08:07 -04:00
}
2022-04-22 17:11:57 -04:00
void FRDGBuilder : : InitRHI ( FRDGTextureUAVRef UAV )
2018-10-22 23:01:29 -04:00
{
check ( UAV ) ;
2021-05-19 17:54:58 -04:00
if ( UAV - > HasRHI ( ) )
2018-10-22 23:01:29 -04:00
{
return ;
}
2019-10-01 13:03:04 -04:00
FRDGTextureRef Texture = UAV - > Desc . Texture ;
2021-04-26 14:12:08 -04:00
FRHITexture * TextureRHI = Texture - > GetRHIUnchecked ( ) ;
check ( TextureRHI ) ;
2019-10-01 13:03:04 -04:00
2021-04-26 14:12:08 -04:00
UAV - > ResourceRHI = Texture - > ViewCache - > GetOrCreateUAV ( TextureRHI , UAV - > Desc ) ;
2018-10-22 23:01:29 -04:00
}
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : BeginResourceRHI ( FRDGPassHandle PassHandle , FRDGBufferRef Buffer )
2019-06-18 13:23:41 -04:00
{
check ( Buffer ) ;
2020-09-24 00:43:27 -04:00
2021-05-19 17:54:58 -04:00
if ( Buffer - > HasRHI ( ) )
2019-06-18 13:23:41 -04:00
{
return ;
}
2021-03-17 12:44:59 -04:00
check ( Buffer - > ReferenceCount > 0 | | Buffer - > bExternal | | IsImmediateMode ( ) ) ;
2019-06-18 13:23:41 -04:00
2021-05-25 17:11:34 -04:00
# if RDG_ENABLE_DEBUG
{
const FRDGPass * Pass = Passes [ PassHandle ] ;
// Cannot begin a resource on an async compute pass.
check ( Pass - > Pipeline = = ERHIPipeline : : Graphics ) ;
// Cannot begin a resource within a merged render pass region.
2022-01-20 16:30:26 -05:00
checkf ( GetPrologueBarrierPassHandle ( PassHandle ) = = PassHandle ,
TEXT ( " Cannot begin a resource within a merged render pass. Pass (Handle: %d, Name: %s), Resource %s " ) , PassHandle , Pass - > GetName ( ) , Buffer - > Name ) ;
2021-05-25 17:11:34 -04:00
}
# endif
2021-06-07 12:19:06 -04:00
Buffer - > FinalizeDesc ( ) ;
2021-05-25 17:11:34 -04:00
2021-03-17 12:44:59 -04:00
// If transient then create the resource on the transient allocator. External or extracted resource can't be transient because of lifetime tracking issues.
2022-01-03 18:28:16 -05:00
if ( TransientResourceAllocator & & IsTransient ( Buffer ) )
2021-03-17 12:44:59 -04:00
{
2022-01-03 18:28:16 -05:00
if ( FRHITransientBuffer * TransientBuffer = TransientResourceAllocator - > CreateBuffer ( Translate ( Buffer - > Desc ) , Buffer - > Name , PassHandle . GetIndex ( ) ) )
2021-03-17 12:44:59 -04:00
{
2022-03-25 11:19:10 -04:00
SetRHI ( Buffer , TransientBuffer , PassHandle ) ;
2021-04-21 13:03:28 -04:00
2022-04-01 13:05:11 -04:00
const FRDGPassHandle MinAcquirePassHandle ( TransientBuffer - > GetAcquirePasses ( ) . Min ) ;
AddAliasingTransition ( MinAcquirePassHandle , PassHandle , Buffer , FRHITransientAliasingInfo : : Acquire ( TransientBuffer - > GetRHI ( ) , TransientBuffer - > GetAliasingOverlaps ( ) ) ) ;
FRDGSubresourceState * InitialState = Buffer - > State ;
InitialState - > SetPass ( ERHIPipeline : : Graphics , MinAcquirePassHandle ) ;
InitialState - > Access = ERHIAccess : : Discard ;
2022-01-03 18:28:16 -05:00
# if STATS
GRDGStatTransientBufferCount + + ;
# endif
2021-03-17 12:44:59 -04:00
}
}
2021-04-21 13:03:28 -04:00
if ( ! Buffer - > bTransient )
2021-03-17 12:44:59 -04:00
{
2022-04-22 17:11:57 -04:00
const ERDGPooledBufferAlignment Alignment = Buffer - > bQueuedForUpload ? ERDGPooledBufferAlignment : : PowerOfTwo : ERDGPooledBufferAlignment : : Page ;
SetRHI ( Buffer , GRenderGraphResourcePool . FindFreeBuffer ( Buffer - > Desc , Buffer - > Name , Alignment ) , PassHandle ) ;
2021-03-17 12:44:59 -04:00
}
2019-06-18 13:23:41 -04:00
}
2022-04-22 17:11:57 -04:00
void FRDGBuilder : : InitRHI ( FRDGBufferSRVRef SRV )
2018-10-22 23:01:29 -04:00
{
check ( SRV ) ;
2021-05-19 17:54:58 -04:00
if ( SRV - > HasRHI ( ) )
2018-10-22 23:01:29 -04:00
{
return ;
}
2019-06-11 18:27:07 -04:00
FRDGBufferRef Buffer = SRV - > Desc . Buffer ;
2021-04-26 14:12:08 -04:00
FRHIBuffer * BufferRHI = Buffer - > GetRHIUnchecked ( ) ;
check ( BufferRHI ) ;
2019-06-11 18:27:07 -04:00
2021-04-21 13:03:28 -04:00
FRHIBufferSRVCreateInfo SRVCreateInfo = SRV - > Desc ;
2022-05-06 15:44:23 -04:00
if ( EnumHasAnyFlags ( Buffer - > Desc . Usage , EBufferUsageFlags : : StructuredBuffer ) )
2021-04-21 13:03:28 -04:00
{
// RDG allows structured buffer views to be typed, but the view creation logic requires that it
// be unknown (as do platform APIs -- structured buffers are not typed). This could be validated
// at the high level but the current API makes it confusing. For now, it's considered a no-op.
SRVCreateInfo . Format = PF_Unknown ;
}
2021-04-26 14:12:08 -04:00
SRV - > ResourceRHI = Buffer - > ViewCache - > GetOrCreateSRV ( BufferRHI , SRVCreateInfo ) ;
2018-10-22 23:01:29 -04:00
}
2022-04-22 17:11:57 -04:00
void FRDGBuilder : : InitRHI ( FRDGBufferUAV * UAV )
2018-10-22 23:01:29 -04:00
{
check ( UAV ) ;
2021-05-19 17:54:58 -04:00
if ( UAV - > HasRHI ( ) )
2018-10-22 23:01:29 -04:00
{
return ;
}
2020-07-06 18:58:26 -04:00
2019-01-15 19:57:23 -05:00
FRDGBufferRef Buffer = UAV - > Desc . Buffer ;
2021-05-05 11:58:15 -04:00
check ( Buffer ) ;
2021-04-21 13:03:28 -04:00
FRHIBufferUAVCreateInfo UAVCreateInfo = UAV - > Desc ;
2022-05-06 15:44:23 -04:00
if ( EnumHasAnyFlags ( Buffer - > Desc . Usage , EBufferUsageFlags : : StructuredBuffer ) )
2021-04-21 13:03:28 -04:00
{
// RDG allows structured buffer views to be typed, but the view creation logic requires that it
// be unknown (as do platform APIs -- structured buffers are not typed). This could be validated
// at the high level but the current API makes it confusing. For now, it's considered a no-op.
UAVCreateInfo . Format = PF_Unknown ;
}
2021-04-26 14:12:08 -04:00
UAV - > ResourceRHI = Buffer - > ViewCache - > GetOrCreateUAV ( Buffer - > GetRHIUnchecked ( ) , UAVCreateInfo ) ;
2018-10-22 23:01:29 -04:00
}
2022-04-22 17:11:57 -04:00
void FRDGBuilder : : InitRHI ( FRDGView * View )
2021-05-05 11:58:15 -04:00
{
2021-05-19 17:54:58 -04:00
if ( View - > HasRHI ( ) )
2021-05-05 11:58:15 -04:00
{
return ;
}
switch ( View - > Type )
{
case ERDGViewType : : TextureUAV :
2022-04-22 17:11:57 -04:00
InitRHI ( static_cast < FRDGTextureUAV * > ( View ) ) ;
2021-05-05 11:58:15 -04:00
break ;
case ERDGViewType : : TextureSRV :
2022-04-22 17:11:57 -04:00
InitRHI ( static_cast < FRDGTextureSRV * > ( View ) ) ;
2021-05-05 11:58:15 -04:00
break ;
case ERDGViewType : : BufferUAV :
2022-04-22 17:11:57 -04:00
InitRHI ( static_cast < FRDGBufferUAV * > ( View ) ) ;
2021-05-05 11:58:15 -04:00
break ;
case ERDGViewType : : BufferSRV :
2022-04-22 17:11:57 -04:00
InitRHI ( static_cast < FRDGBufferSRV * > ( View ) ) ;
2021-05-05 11:58:15 -04:00
break ;
}
}
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : EndResourceRHI ( FRDGPassHandle PassHandle , FRDGTextureRef Texture , uint32 ReferenceCount )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
check ( Texture ) ;
2021-03-17 12:44:59 -04:00
check ( Texture - > ReferenceCount > = ReferenceCount | | IsImmediateMode ( ) ) ;
Texture - > ReferenceCount - = ReferenceCount ;
2020-09-24 00:43:27 -04:00
2021-03-17 12:44:59 -04:00
if ( Texture - > ReferenceCount = = 0 )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2021-03-17 12:44:59 -04:00
if ( Texture - > bTransient )
{
2022-01-03 18:28:16 -05:00
// Texture is using a transient external render target.
2022-03-25 11:19:10 -04:00
if ( Texture - > RenderTarget )
2022-01-03 18:28:16 -05:00
{
2022-04-05 13:14:19 -04:00
if ( ! Texture - > bExtracted )
{
// This releases the reference without invoking a virtual function call.
GRDGTransientResourceAllocator . Release ( TRefCountPtr < FRDGTransientRenderTarget > ( MoveTemp ( Texture - > Allocation ) ) , PassHandle ) ;
}
2022-01-03 18:28:16 -05:00
}
// Texture is using an internal transient texture.
else
{
TransientResourceAllocator - > DeallocateMemory ( Texture - > TransientTexture , PassHandle . GetIndex ( ) ) ;
}
2021-03-17 12:44:59 -04:00
}
2022-01-03 18:28:16 -05:00
else
2021-04-08 00:39:34 -04:00
{
2022-01-03 18:28:16 -05:00
// Only tracked render targets are released. Untracked ones persist until the end of the frame.
2022-03-25 11:19:10 -04:00
if ( static_cast < FPooledRenderTarget * > ( Texture - > RenderTarget ) - > IsTracked ( ) )
2022-01-03 18:28:16 -05:00
{
// This releases the reference without invoking a virtual function call.
TRefCountPtr < FPooledRenderTarget > ( MoveTemp ( Texture - > Allocation ) ) ;
}
2021-04-08 00:39:34 -04:00
}
2021-03-17 12:44:59 -04:00
Texture - > LastPass = PassHandle ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
2021-05-19 17:54:58 -04:00
void FRDGBuilder : : EndResourceRHI ( FRDGPassHandle PassHandle , FRDGBufferRef Buffer , uint32 ReferenceCount )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
check ( Buffer ) ;
2021-03-17 12:44:59 -04:00
check ( Buffer - > ReferenceCount > = ReferenceCount | | IsImmediateMode ( ) ) ;
Buffer - > ReferenceCount - = ReferenceCount ;
2020-09-24 00:43:27 -04:00
2021-03-17 12:44:59 -04:00
if ( Buffer - > ReferenceCount = = 0 )
2019-11-13 13:12:15 -05:00
{
2021-03-17 12:44:59 -04:00
if ( Buffer - > bTransient )
{
2021-08-16 17:32:38 -04:00
TransientResourceAllocator - > DeallocateMemory ( Buffer - > TransientBuffer , PassHandle . GetIndex ( ) ) ;
2021-03-17 12:44:59 -04:00
}
2021-04-08 00:39:34 -04:00
else
{
Buffer - > Allocation = nullptr ;
}
2021-03-17 12:44:59 -04:00
Buffer - > LastPass = PassHandle ;
2019-11-13 13:12:15 -05:00
}
2020-07-06 18:58:26 -04:00
}
2019-11-13 13:12:15 -05:00
2022-03-25 11:19:10 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////
2020-07-06 18:58:26 -04:00
# if RDG_ENABLE_DEBUG
void FRDGBuilder : : VisualizePassOutputs ( const FRDGPass * Pass )
{
# if SUPPORTS_VISUALIZE_TEXTURE
2022-05-04 12:41:19 -04:00
if ( bInVisualizePassOutputs )
2020-07-06 18:58:26 -04:00
{
return ;
}
2022-05-04 12:41:19 -04:00
bInVisualizePassOutputs = true ;
2021-12-03 02:41:52 -05:00
2020-09-24 00:43:27 -04:00
Pass - > GetParameters ( ) . EnumerateTextures ( [ & ] ( FRDGParameter Parameter )
2020-07-06 18:58:26 -04:00
{
2019-06-11 18:27:07 -04:00
switch ( Parameter . GetType ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
case UBMT_RDG_TEXTURE_ACCESS :
{
if ( FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) )
{
if ( TextureAccess . GetAccess ( ) = = ERHIAccess : : UAVCompute | |
TextureAccess . GetAccess ( ) = = ERHIAccess : : UAVGraphics | |
TextureAccess . GetAccess ( ) = = ERHIAccess : : RTV )
{
if ( TOptional < uint32 > CaptureId = GVisualizeTexture . ShouldCapture ( TextureAccess - > Name , /* MipIndex = */ 0 ) )
{
GVisualizeTexture . CreateContentCapturePass ( * this , TextureAccess . GetTexture ( ) , * CaptureId ) ;
}
}
}
}
break ;
2019-01-04 14:52:46 -05:00
case UBMT_RDG_TEXTURE_UAV :
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
if ( FRDGTextureUAVRef UAV = Parameter . GetAsTextureUAV ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
FRDGTextureRef Texture = UAV - > Desc . Texture ;
2020-09-24 00:43:27 -04:00
if ( TOptional < uint32 > CaptureId = GVisualizeTexture . ShouldCapture ( Texture - > Name , UAV - > Desc . MipLevel ) )
2019-09-03 19:19:28 -04:00
{
2020-09-24 00:43:27 -04:00
GVisualizeTexture . CreateContentCapturePass ( * this , Texture , * CaptureId ) ;
2019-09-03 19:19:28 -04:00
}
2018-10-22 23:01:29 -04:00
}
}
break ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
case UBMT_RENDER_TARGET_BINDING_SLOTS :
{
2020-07-06 18:58:26 -04:00
const FRenderTargetBindingSlots & RenderTargets = Parameter . GetAsRenderTargetBindingSlots ( ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-07-06 18:58:26 -04:00
RenderTargets . Enumerate ( [ & ] ( FRenderTargetBinding RenderTarget )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
FRDGTextureRef Texture = RenderTarget . GetTexture ( ) ;
2020-09-24 00:43:27 -04:00
if ( TOptional < uint32 > CaptureId = GVisualizeTexture . ShouldCapture ( Texture - > Name , RenderTarget . GetMipIndex ( ) ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-09-24 00:43:27 -04:00
GVisualizeTexture . CreateContentCapturePass ( * this , Texture , * CaptureId ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
const FDepthStencilBinding & DepthStencil = RenderTargets . DepthStencil ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2019-06-11 18:27:07 -04:00
if ( FRDGTextureRef Texture = DepthStencil . GetTexture ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
const bool bHasStoreAction = DepthStencil . GetDepthStencilAccess ( ) . IsAnyWrite ( ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-07-06 18:58:26 -04:00
if ( bHasStoreAction )
{
2020-09-24 00:43:27 -04:00
const uint32 MipIndex = 0 ;
if ( TOptional < uint32 > CaptureId = GVisualizeTexture . ShouldCapture ( Texture - > Name , MipIndex ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
GVisualizeTexture . CreateContentCapturePass ( * this , Texture , * CaptureId ) ;
2020-07-06 18:58:26 -04:00
}
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
break ;
}
2020-09-24 00:43:27 -04:00
} ) ;
2021-12-03 02:41:52 -05:00
2022-05-04 12:41:19 -04:00
bInVisualizePassOutputs = false ;
2020-07-06 18:58:26 -04:00
# endif
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
void FRDGBuilder : : ClobberPassOutputs ( const FRDGPass * Pass )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2022-05-04 12:41:19 -04:00
if ( ! GRDGClobberResources | | bInClobberPassOutputs )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
return ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2022-05-04 12:41:19 -04:00
bInClobberPassOutputs = true ;
2018-10-22 23:01:29 -04:00
2020-07-06 18:58:26 -04:00
RDG_EVENT_SCOPE ( * this , " RDG ClobberResources " ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-07-06 18:58:26 -04:00
const FLinearColor ClobberColor = GetClobberColor ( ) ;
2019-06-11 18:27:07 -04:00
2020-09-24 00:43:27 -04:00
Pass - > GetParameters ( ) . Enumerate ( [ & ] ( FRDGParameter Parameter )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
switch ( Parameter . GetType ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
case UBMT_RDG_BUFFER_UAV :
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
if ( FRDGBufferUAVRef UAV = Parameter . GetAsBufferUAV ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
FRDGBufferRef Buffer = UAV - > GetParent ( ) ;
if ( UserValidation . TryMarkForClobber ( Buffer ) )
{
2020-09-24 00:43:27 -04:00
AddClearUAVPass ( * this , UAV , GetClobberBufferValue ( ) ) ;
}
}
}
break ;
case UBMT_RDG_TEXTURE_ACCESS :
{
if ( FRDGTextureAccess TextureAccess = Parameter . GetAsTextureAccess ( ) )
{
FRDGTextureRef Texture = TextureAccess . GetTexture ( ) ;
if ( UserValidation . TryMarkForClobber ( Texture ) )
{
if ( EnumHasAnyFlags ( TextureAccess . GetAccess ( ) , ERHIAccess : : UAVMask ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
for ( int32 MipLevel = 0 ; MipLevel < Texture - > Desc . NumMips ; MipLevel + + )
{
2021-04-02 20:35:50 -04:00
AddClearUAVPass ( * this , CreateUAV ( FRDGTextureUAVDesc ( Texture , MipLevel ) ) , ClobberColor ) ;
2020-09-24 00:43:27 -04:00
}
2020-07-06 18:58:26 -04:00
}
2020-09-24 00:43:27 -04:00
else if ( EnumHasAnyFlags ( TextureAccess . GetAccess ( ) , ERHIAccess : : RTV ) )
2020-07-06 18:58:26 -04:00
{
2020-09-24 00:43:27 -04:00
AddClearRenderTargetPass ( * this , Texture , ClobberColor ) ;
2020-07-06 18:58:26 -04:00
}
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
break ;
2019-01-04 14:52:46 -05:00
case UBMT_RDG_TEXTURE_UAV :
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2019-06-11 18:27:07 -04:00
if ( FRDGTextureUAVRef UAV = Parameter . GetAsTextureUAV ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
FRDGTextureRef Texture = UAV - > GetParent ( ) ;
if ( UserValidation . TryMarkForClobber ( Texture ) )
{
if ( Texture - > Desc . NumMips = = 1 )
{
AddClearUAVPass ( * this , UAV , ClobberColor ) ;
}
else
{
for ( int32 MipLevel = 0 ; MipLevel < Texture - > Desc . NumMips ; MipLevel + + )
{
2021-04-02 20:35:50 -04:00
AddClearUAVPass ( * this , CreateUAV ( FRDGTextureUAVDesc ( Texture , MipLevel ) ) , ClobberColor ) ;
2020-07-06 18:58:26 -04:00
}
}
}
2018-10-22 23:01:29 -04:00
}
}
break ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
case UBMT_RENDER_TARGET_BINDING_SLOTS :
{
2020-07-06 18:58:26 -04:00
const FRenderTargetBindingSlots & RenderTargets = Parameter . GetAsRenderTargetBindingSlots ( ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
2020-07-06 18:58:26 -04:00
RenderTargets . Enumerate ( [ & ] ( FRenderTargetBinding RenderTarget )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
FRDGTextureRef Texture = RenderTarget . GetTexture ( ) ;
2019-06-11 18:27:07 -04:00
2020-07-06 18:58:26 -04:00
if ( UserValidation . TryMarkForClobber ( Texture ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
AddClearRenderTargetPass ( * this , Texture , ClobberColor ) ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
2020-07-06 18:58:26 -04:00
} ) ;
2019-06-11 18:27:07 -04:00
2020-07-06 18:58:26 -04:00
if ( FRDGTextureRef Texture = RenderTargets . DepthStencil . GetTexture ( ) )
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
{
2020-07-06 18:58:26 -04:00
if ( UserValidation . TryMarkForClobber ( Texture ) )
{
AddClearDepthStencilPass ( * this , Texture , true , GetClobberDepth ( ) , true , GetClobberStencil ( ) ) ;
}
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
}
break ;
2019-06-11 18:27:07 -04:00
}
2020-09-24 00:43:27 -04:00
} ) ;
2019-06-11 18:27:07 -04:00
2022-05-04 12:41:19 -04:00
bInClobberPassOutputs = false ;
Merging //UE4/Dev-Rendering-Graph@4492585 to Dev-Rendering (//UE4/Dev-Rendering)
This implements the framework to write the high level rendering code into passes organized in direct acyclic graph. It is also unifying the uniform buffer, shader parameters, and pass parameters to same single API: structures with run time meta data. This allow high level user code be extremely seamless, user code debugging, and render graph ease of implementation and debugging.
Issue of collaborative work of Arne Schnober, Brian Karis, Daniel Wright, Marcus Wassmer and Guillaume Abadie.
Names of the graph managed resources are not final.
#rb Arne.Schnober, Brian.Karis, Daniel.Wright, Marcus.Wassmer
[CL 4492694 by Guillaume Abadie in Dev-Rendering branch]
2018-10-19 17:36:35 -04:00
}
UE5_RELEASE: MGPU, numerous fixes to get EngineTest AFR, and Virtual Production City map to run with multiple GPUs. Ultimately there were 3 crash sources (RayTracing, Nanite, Distance Field streaming), each of which required a couple fixes, plus infrastructure to support those fixes...
There remain significant visual artifacts in the Virtual Production City map. Lumen has serious issues with multiple views in both single and multi-GPU modes -- I think Lumen data needs to be split per view family to solve this. There is some corrupt geometry in the second view, which may be Nanite or instance rendering related (or something else entirely). To narrow down these issues, I think I'm going to need to extend the DumpGPU feature to be able to do more effective MGPU graphical debugging, since none of PIX, RenderDoc, or NSight work. But at least it doesn't crash now...
Full list of changes:
* CVAR (DC.MultiGPUMode) to override multi-GPU mode for Display Cluster, debug feature copied over from 4.27.
* Barrier and synchronization fixes for RHITransferTextures copied over 4.27. Future work will make RDG handle multi-GPU transitions more seamlessly...
* CVAR (DC.ForceCrossGPUCopy) to force expensive full synchronization and copy of resources cross GPU at the end of each view family render (for debugging). RHITransferTextures upgraded to support copying things besides 2D textures, including other texture resources and buffers.
* AFR temporal fixes from a previous CL (which I moved from my single GPU to multi GPU PC), now improved to avoid some validation asserts in Debug builds (pass inputs not declared, GetParent()->GetRHI() not working because parent not declared to pass).
* Ray tracing (hang): acceleration buffers are branched per GPU, as GPU virtual addresses for resources internally referenced by these buffers may vary per GPU. Needed to add infrastructure to support buffers that duplicate memory per GPU, rather than using driver aliasing of the underlying resource.
* Ray tracing (hang): some buffer bindings weren't using a proper GPU index.
* Nanite (hang): Force initial clear of Nanite.MainAndPostNodesAndClusterBatchesBuffer to run on all GPUs. Solves GPU hang in shadow rendering the first frame (due to shadow rendering running across all GPUs), and later random hangs in view rendering.
* Distance field streaming (assert): GPU readback staging buffers need to be branched per GPU, as the underlying class is single device. GPU readback buffers and textures properly take into account the GPU they were last written on when locking and unlocking. Includes handling an edge case where a write can be queued when a lock is active, due to the deferred way commands are played back in the render graph.
* Distance field streaming (assert): UAV clear wasn't taking into account GPU index.
* GPU scene update needs to run across all GPUs.
* Fix for "DumpGPU" command to avoid assert with MGPU -- arbitrarily pick a GPU (last index) when the GPU mask contains multiple bits. Hope to improve this in the future, but it works.
#rnx
#rb mihnea.balta juan.canada tiago.costa kenzo.terelst
#jira none
#preflight 61ba7edbdc58e54b3318fdf5
#ROBOMERGE-AUTHOR: jason.hoerner
#ROBOMERGE-SOURCE: CL 18472819 in //UE5/Release-5.0/... via CL 18473380
#ROBOMERGE-BOT: STARSHIP (Release-Engine-Staging -> Release-Engine-Test) (v899-18417669)
[CL 18473412 by jason hoerner in ue5-release-engine-test branch]
2021-12-15 23:12:04 -05:00
# endif //! RDG_ENABLE_DEBUG
# if WITH_MGPU
void FRDGBuilder : : ForceCopyCrossGPU ( )
{
// Initialize set of external buffers
TSet < FRHIBuffer * > ExternalBufferSet ;
ExternalBufferSet . Reserve ( ExternalBuffers . Num ( ) ) ;
for ( auto ExternalBufferIt = ExternalBuffers . CreateConstIterator ( ) ; ExternalBufferIt ; + + ExternalBufferIt )
{
ExternalBufferSet . Emplace ( ExternalBufferIt . Value ( ) - > GetRHIUnchecked ( ) ) ;
}
// Generate list of cross GPU resources from all passes, and the GPU mask where they were last written
TMap < FRHIBuffer * , FRHIGPUMask > BuffersToTransfer ;
TMap < FRHITexture * , FRHIGPUMask > TexturesToTransfer ;
for ( FRDGPassHandle PassHandle = GetProloguePassHandle ( ) ; PassHandle < = GetEpiloguePassHandle ( ) ; + + PassHandle )
{
FRDGPass * Pass = Passes [ PassHandle ] ;
for ( int32 BufferIndex = 0 ; BufferIndex < Pass - > BufferStates . Num ( ) ; BufferIndex + + )
{
FRHIBuffer * BufferRHI = Pass - > BufferStates [ BufferIndex ] . Buffer - > GetRHIUnchecked ( ) ;
if ( ExternalBufferSet . Contains ( BufferRHI ) & &
! EnumHasAnyFlags ( BufferRHI - > GetUsage ( ) , BUF_MultiGPUAllocate | BUF_MultiGPUGraphIgnore ) & &
EnumHasAnyFlags ( Pass - > BufferStates [ BufferIndex ] . State . Access , ERHIAccess : : WritableMask ) )
{
BuffersToTransfer . Emplace ( BufferRHI ) = Pass - > GPUMask ;
}
}
for ( int32 TextureIndex = 0 ; TextureIndex < Pass - > TextureStates . Num ( ) ; TextureIndex + + )
{
if ( ExternalTextures . Contains ( Pass - > TextureStates [ TextureIndex ] . Texture - > GetRHIUnchecked ( ) ) )
{
for ( int32 StateIndex = 0 ; StateIndex < Pass - > TextureStates [ TextureIndex ] . State . Num ( ) ; StateIndex + + )
{
FRHITexture * TextureRHI = Pass - > TextureStates [ TextureIndex ] . Texture - > GetRHIUnchecked ( ) ;
if ( TextureRHI & &
! EnumHasAnyFlags ( TextureRHI - > GetFlags ( ) , TexCreate_MultiGPUGraphIgnore ) & &
EnumHasAnyFlags ( Pass - > TextureStates [ TextureIndex ] . State [ StateIndex ] . Access , ERHIAccess : : WritableMask ) )
{
TexturesToTransfer . Emplace ( Pass - > TextureStates [ TextureIndex ] . Texture - > GetRHIUnchecked ( ) ) = Pass - > GPUMask ;
}
}
}
}
}
// Now that we've got the list of external resources, and the GPU they were last written to, make a list of what needs to
// be propagated to other GPUs.
TArray < FTransferResourceParams > Transfers ;
const FRHIGPUMask AllGPUMask = FRHIGPUMask : : All ( ) ;
const bool bPullData = false ;
const bool bLockstepGPUs = true ;
for ( auto BufferIt = BuffersToTransfer . CreateConstIterator ( ) ; BufferIt ; + + BufferIt )
{
FRHIBuffer * Buffer = BufferIt . Key ( ) ;
FRHIGPUMask GPUMask = BufferIt . Value ( ) ;
for ( uint32 GPUIndex : AllGPUMask )
{
if ( ! GPUMask . Contains ( GPUIndex ) )
{
Transfers . Add ( FTransferResourceParams ( Buffer , GPUMask . GetFirstIndex ( ) , GPUIndex , bPullData , bLockstepGPUs ) ) ;
}
}
}
for ( auto TextureIt = TexturesToTransfer . CreateConstIterator ( ) ; TextureIt ; + + TextureIt )
{
FRHITexture * Texture = TextureIt . Key ( ) ;
FRHIGPUMask GPUMask = TextureIt . Value ( ) ;
for ( uint32 GPUIndex : AllGPUMask )
{
if ( ! GPUMask . Contains ( GPUIndex ) )
{
Transfers . Add ( FTransferResourceParams ( Texture , GPUMask . GetFirstIndex ( ) , GPUIndex , bPullData , bLockstepGPUs ) ) ;
}
}
}
if ( Transfers . Num ( ) )
{
RHICmdList . TransferResources ( Transfers ) ;
}
}
# endif // WITH_MGPU