2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-12-18 21:41:17 -05:00
# include "MeshMaterialShader.h"
# include "ScenePrivate.h"
2019-03-07 11:25:32 -05:00
# include "RayTracingDynamicGeometryCollection.h"
2021-04-05 14:26:31 -04:00
# include "RayTracingInstance.h"
2018-12-18 21:41:17 -05:00
# if RHI_RAYTRACING
2021-12-03 12:53:31 -05:00
static int32 GRTDynGeomSharedVertexBufferSizeInMB = 4 ;
static FAutoConsoleVariableRef CVarRTDynGeomSharedVertexBufferSizeInMB (
TEXT ( " r.RayTracing.DynamicGeometry.SharedVertexBufferSizeInMB " ) ,
GRTDynGeomSharedVertexBufferSizeInMB ,
TEXT ( " Size of the a single shared vertex buffer used during the BLAS update of dynamic geometries (default 4MB) " ) ,
ECVF_RenderThreadSafe
) ;
static int32 GRTDynGeomSharedVertexBufferGarbageCollectLatency = 30 ;
static FAutoConsoleVariableRef CVarRTDynGeomSharedVertexBufferGarbageCollectLatency (
2021-12-03 13:04:29 -05:00
TEXT ( " r.RayTracing.DynamicGeometry.SharedVertexBufferGarbageCollectLatency " ) ,
2021-12-03 12:53:31 -05:00
GRTDynGeomSharedVertexBufferGarbageCollectLatency ,
TEXT ( " Amount of update cycles before a heap is deleted when not used (default 30). " ) ,
ECVF_RenderThreadSafe
) ;
2020-08-11 01:36:57 -04:00
DECLARE_CYCLE_STAT ( TEXT ( " RTDynGeomDispatch " ) , STAT_CLM_RTDynGeomDispatch , STATGROUP_ParallelCommandListMarkers ) ;
DECLARE_CYCLE_STAT ( TEXT ( " RTDynGeomBuild " ) , STAT_CLM_RTDynGeomBuild , STATGROUP_ParallelCommandListMarkers ) ;
2021-02-18 18:13:28 -04:00
// Workaround for outstanding memory corruption on some platforms when parallel command list translation is used.
# define USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS 0
2018-12-18 21:41:17 -05:00
class FRayTracingDynamicGeometryConverterCS : public FMeshMaterialShader
{
DECLARE_SHADER_TYPE ( FRayTracingDynamicGeometryConverterCS , MeshMaterial ) ;
public :
FRayTracingDynamicGeometryConverterCS ( const FMeshMaterialShaderType : : CompiledShaderInitializerType & Initializer )
: FMeshMaterialShader ( Initializer )
{
2020-09-24 00:43:27 -04:00
PassUniformBuffer . Bind ( Initializer . ParameterMap , FSceneTextureUniformParameters : : StaticStructMetadata . GetShaderVariableName ( ) ) ;
2018-12-18 21:41:17 -05:00
RWVertexPositions . Bind ( Initializer . ParameterMap , TEXT ( " VertexPositions " ) ) ;
2020-11-24 18:42:39 -04:00
UsingIndirectDraw . Bind ( Initializer . ParameterMap , TEXT ( " UsingIndirectDraw " ) ) ;
2019-06-17 15:42:30 -04:00
NumVertices . Bind ( Initializer . ParameterMap , TEXT ( " NumVertices " ) ) ;
MinVertexIndex . Bind ( Initializer . ParameterMap , TEXT ( " MinVertexIndex " ) ) ;
2019-10-01 13:03:04 -04:00
PrimitiveId . Bind ( Initializer . ParameterMap , TEXT ( " PrimitiveId " ) ) ;
2020-08-11 01:36:57 -04:00
OutputVertexBaseIndex . Bind ( Initializer . ParameterMap , TEXT ( " OutputVertexBaseIndex " ) ) ;
2020-06-23 18:40:00 -04:00
bApplyWorldPositionOffset . Bind ( Initializer . ParameterMap , TEXT ( " bApplyWorldPositionOffset " ) ) ;
2022-02-02 05:56:37 -05:00
InstanceId . Bind ( Initializer . ParameterMap , TEXT ( " InstanceId " ) ) ;
WorldToInstance . Bind ( Initializer . ParameterMap , TEXT ( " WorldToInstance " ) ) ;
2018-12-18 21:41:17 -05:00
}
FRayTracingDynamicGeometryConverterCS ( ) = default ;
2019-06-11 18:27:07 -04:00
static bool ShouldCompilePermutation ( const FMeshMaterialShaderPermutationParameters & Parameters )
2018-12-18 21:41:17 -05:00
{
2021-04-05 14:26:31 -04:00
return Parameters . VertexFactoryType - > SupportsRayTracingDynamicGeometry ( ) & & ShouldCompileRayTracingShadersForProject ( Parameters . Platform ) ;
2018-12-18 21:41:17 -05:00
}
2021-04-08 14:32:07 -04:00
static void ModifyCompilationEnvironment ( const FMaterialShaderPermutationParameters & Parameters , FShaderCompilerEnvironment & OutEnvironment )
{
OutEnvironment . SetDefine ( TEXT ( " SCENE_TEXTURES_DISABLED " ) , 1 ) ;
}
2018-12-18 21:41:17 -05:00
void GetShaderBindings (
const FScene * Scene ,
ERHIFeatureLevel : : Type FeatureLevel ,
const FPrimitiveSceneProxy * PrimitiveSceneProxy ,
const FMaterialRenderProxy & MaterialRenderProxy ,
const FMaterial & Material ,
2019-01-17 05:02:52 -05:00
const FMeshPassProcessorRenderState & DrawRenderState ,
2018-12-18 21:41:17 -05:00
const FMeshMaterialShaderElementData & ShaderElementData ,
FMeshDrawSingleShaderBindings & ShaderBindings ) const
{
2019-01-17 05:02:52 -05:00
FMeshMaterialShader : : GetShaderBindings ( Scene , FeatureLevel , PrimitiveSceneProxy , MaterialRenderProxy , Material , DrawRenderState , ShaderElementData , ShaderBindings ) ;
2018-12-18 21:41:17 -05:00
}
void GetElementShaderBindings (
2020-02-06 13:13:41 -05:00
const FShaderMapPointerTable & PointerTable ,
2018-12-18 21:41:17 -05:00
const FScene * Scene ,
const FSceneView * ViewIfDynamicMeshCommand ,
const FVertexFactory * VertexFactory ,
2019-06-11 18:27:07 -04:00
const EVertexInputStreamType InputStreamType ,
2018-12-18 21:41:17 -05:00
ERHIFeatureLevel : : Type FeatureLevel ,
const FPrimitiveSceneProxy * PrimitiveSceneProxy ,
const FMeshBatch & MeshBatch ,
const FMeshBatchElement & BatchElement ,
const FMeshMaterialShaderElementData & ShaderElementData ,
FMeshDrawSingleShaderBindings & ShaderBindings ,
FVertexInputStreamArray & VertexStreams ) const
{
2020-02-06 13:13:41 -05:00
FMeshMaterialShader : : GetElementShaderBindings ( PointerTable , Scene , ViewIfDynamicMeshCommand , VertexFactory , InputStreamType , FeatureLevel , PrimitiveSceneProxy , MeshBatch , BatchElement , ShaderElementData , ShaderBindings , VertexStreams ) ;
2018-12-18 21:41:17 -05:00
}
2020-02-06 13:13:41 -05:00
LAYOUT_FIELD ( FRWShaderParameter , RWVertexPositions ) ;
2020-11-24 18:42:39 -04:00
LAYOUT_FIELD ( FShaderParameter , UsingIndirectDraw ) ;
2020-02-06 13:13:41 -05:00
LAYOUT_FIELD ( FShaderParameter , NumVertices ) ;
LAYOUT_FIELD ( FShaderParameter , MinVertexIndex ) ;
LAYOUT_FIELD ( FShaderParameter , PrimitiveId ) ;
2020-06-23 18:40:00 -04:00
LAYOUT_FIELD ( FShaderParameter , bApplyWorldPositionOffset ) ;
2020-08-11 01:36:57 -04:00
LAYOUT_FIELD ( FShaderParameter , OutputVertexBaseIndex ) ;
2022-02-02 05:56:37 -05:00
LAYOUT_FIELD ( FShaderParameter , InstanceId ) ;
LAYOUT_FIELD ( FShaderParameter , WorldToInstance ) ;
2018-12-18 21:41:17 -05:00
} ;
IMPLEMENT_MATERIAL_SHADER_TYPE ( , FRayTracingDynamicGeometryConverterCS , TEXT ( " /Engine/Private/RayTracing/RayTracingDynamicMesh.usf " ) , TEXT ( " RayTracingDynamicGeometryConverterCS " ) , SF_Compute ) ;
2020-08-11 01:36:57 -04:00
FRayTracingDynamicGeometryCollection : : FRayTracingDynamicGeometryCollection ( )
2019-03-07 11:25:32 -05:00
{
2020-08-11 01:36:57 -04:00
}
FRayTracingDynamicGeometryCollection : : ~ FRayTracingDynamicGeometryCollection ( )
{
for ( FVertexPositionBuffer * Buffer : VertexPositionBuffers )
{
delete Buffer ;
}
VertexPositionBuffers . Empty ( ) ;
}
2021-04-16 07:20:54 -04:00
int64 FRayTracingDynamicGeometryCollection : : BeginUpdate ( )
2020-08-11 01:36:57 -04:00
{
// Clear working arrays - keep max size allocated
DispatchCommands . Empty ( DispatchCommands . Max ( ) ) ;
BuildParams . Empty ( BuildParams . Max ( ) ) ;
Segments . Empty ( Segments . Max ( ) ) ;
// Vertex buffer data can be immediatly reused the next frame, because it's already 'consumed' for building the AccelerationStructure data
2021-12-03 12:53:31 -05:00
// Garbage collect unused buffers for n generations
for ( int32 BufferIndex = 0 ; BufferIndex < VertexPositionBuffers . Num ( ) ; + + BufferIndex )
2020-08-11 01:36:57 -04:00
{
2021-12-03 12:53:31 -05:00
FVertexPositionBuffer * Buffer = VertexPositionBuffers [ BufferIndex ] ;
2020-08-11 01:36:57 -04:00
Buffer - > UsedSize = 0 ;
2021-12-03 12:53:31 -05:00
if ( Buffer - > LastUsedGenerationID + GRTDynGeomSharedVertexBufferGarbageCollectLatency < = SharedBufferGenerationID )
{
VertexPositionBuffers . RemoveAtSwap ( BufferIndex ) ;
delete Buffer ;
BufferIndex - - ;
}
2020-08-11 01:36:57 -04:00
}
// Increment generation ID used for validation
SharedBufferGenerationID + + ;
2021-04-16 07:20:54 -04:00
return SharedBufferGenerationID ;
2019-03-07 11:25:32 -05:00
}
2018-12-18 21:41:17 -05:00
void FRayTracingDynamicGeometryCollection : : AddDynamicMeshBatchForGeometryUpdate (
2020-08-11 01:36:57 -04:00
const FScene * Scene ,
const FSceneView * View ,
const FPrimitiveSceneProxy * PrimitiveSceneProxy ,
2019-10-01 13:03:04 -04:00
FRayTracingDynamicGeometryUpdateParams UpdateParams ,
uint32 PrimitiveId
2019-06-11 18:27:07 -04:00
)
2018-12-18 21:41:17 -05:00
{
2019-06-11 18:27:07 -04:00
FRayTracingGeometry & Geometry = * UpdateParams . Geometry ;
bool bUsingIndirectDraw = UpdateParams . bUsingIndirectDraw ;
uint32 NumMaxVertices = UpdateParams . NumVertices ;
2020-08-11 01:36:57 -04:00
FRWBuffer * RWBuffer = UpdateParams . Buffer ;
uint32 VertexBufferOffset = 0 ;
bool bUseSharedVertexBuffer = false ;
2021-04-26 06:23:11 -04:00
if ( ReferencedUniformBuffers . Num ( ) = = 0 | | ReferencedUniformBuffers . Last ( ) ! = View - > ViewUniformBuffer )
{
// Keep ViewUniformBuffer alive until EndUpdate()
ReferencedUniformBuffers . Add ( View - > ViewUniformBuffer ) ;
}
2020-08-11 01:36:57 -04:00
// If update params didn't provide a buffer then use a shared vertex position buffer
if ( RWBuffer = = nullptr )
{
FVertexPositionBuffer * VertexPositionBuffer = nullptr ;
for ( FVertexPositionBuffer * Buffer : VertexPositionBuffers )
{
if ( ( Buffer - > RWBuffer . NumBytes - Buffer - > UsedSize ) > = UpdateParams . VertexBufferSize )
{
VertexPositionBuffer = Buffer ;
break ;
}
}
// Allocate a new buffer?
if ( VertexPositionBuffer = = nullptr )
{
VertexPositionBuffer = new FVertexPositionBuffer ;
VertexPositionBuffers . Add ( VertexPositionBuffer ) ;
2021-12-03 12:53:31 -05:00
static const uint32 VertexBufferCacheSize = GRTDynGeomSharedVertexBufferSizeInMB * 1024 * 1024 ;
2020-08-11 01:36:57 -04:00
uint32 AllocationSize = FMath : : Max ( VertexBufferCacheSize , UpdateParams . VertexBufferSize ) ;
2021-02-16 08:37:39 -04:00
VertexPositionBuffer - > RWBuffer . Initialize ( TEXT ( " FRayTracingDynamicGeometryCollection::RayTracingDynamicVertexBuffer " ) , sizeof ( float ) , AllocationSize / sizeof ( float ) , PF_R32_FLOAT , BUF_UnorderedAccess | BUF_ShaderResource ) ;
2020-08-11 01:36:57 -04:00
VertexPositionBuffer - > UsedSize = 0 ;
}
2021-12-03 12:53:31 -05:00
// Update the last used generation ID
VertexPositionBuffer - > LastUsedGenerationID = SharedBufferGenerationID ;
2020-08-11 01:36:57 -04:00
// Get the offset and update used size
VertexBufferOffset = VertexPositionBuffer - > UsedSize ;
VertexPositionBuffer - > UsedSize + = UpdateParams . VertexBufferSize ;
bUseSharedVertexBuffer = true ;
RWBuffer = & VertexPositionBuffer - > RWBuffer ;
}
2019-06-17 15:42:30 -04:00
for ( const FMeshBatch & MeshBatch : UpdateParams . MeshBatches )
{
2021-04-05 14:26:31 -04:00
if ( ! ensureMsgf ( MeshBatch . VertexFactory - > GetType ( ) - > SupportsRayTracingDynamicGeometry ( ) ,
2021-03-30 17:39:32 -04:00
TEXT ( " FRayTracingDynamicGeometryConverterCS doesn't support %s. Skipping rendering of %s. This can happen when the skinning cache runs out of space and falls back to GPUSkinVertexFactory. " ) ,
2021-04-01 06:48:02 -04:00
MeshBatch . VertexFactory - > GetType ( ) - > GetName ( ) , * PrimitiveSceneProxy - > GetOwnerName ( ) . ToString ( ) ) )
2021-03-30 17:39:32 -04:00
{
continue ;
}
2019-06-17 15:42:30 -04:00
const FMaterialRenderProxy * FallbackMaterialRenderProxyPtr = nullptr ;
const FMaterial & Material = MeshBatch . MaterialRenderProxy - > GetMaterialWithFallback ( Scene - > GetFeatureLevel ( ) , FallbackMaterialRenderProxyPtr ) ;
2019-10-01 13:03:04 -04:00
auto * MaterialInterface = Material . GetMaterialInterface ( ) ;
2019-06-17 15:42:30 -04:00
const FMaterialRenderProxy & MaterialRenderProxy = FallbackMaterialRenderProxyPtr ? * FallbackMaterialRenderProxyPtr : * MeshBatch . MaterialRenderProxy ;
2018-12-18 21:41:17 -05:00
2019-06-17 15:42:30 -04:00
TMeshProcessorShaders <
FMeshMaterialShader ,
FMeshMaterialShader ,
FMeshMaterialShader ,
FMeshMaterialShader ,
FRayTracingDynamicGeometryConverterCS > Shaders ;
2018-12-18 21:41:17 -05:00
2019-06-17 15:42:30 -04:00
FMeshComputeDispatchCommand DispatchCmd ;
2018-12-18 21:41:17 -05:00
2022-02-25 14:15:54 -05:00
FMaterialShaderTypes ShaderTypes ;
ShaderTypes . AddShaderType < FRayTracingDynamicGeometryConverterCS > ( ) ;
FMaterialShaders MaterialShaders ;
if ( ! Material . TryGetShaders ( ShaderTypes , MeshBatch . VertexFactory - > GetType ( ) , MaterialShaders ) )
{
continue ;
}
TShaderRef < FRayTracingDynamicGeometryConverterCS > Shader ;
MaterialShaders . TryGetShader ( SF_Compute , Shader ) ;
2019-06-17 15:42:30 -04:00
DispatchCmd . MaterialShader = Shader ;
FMeshDrawShaderBindings & ShaderBindings = DispatchCmd . ShaderBindings ;
2018-12-18 21:41:17 -05:00
2019-06-17 15:42:30 -04:00
Shaders . ComputeShader = Shader ;
ShaderBindings . Initialize ( Shaders . GetUntypedShaders ( ) ) ;
2018-12-18 21:41:17 -05:00
2019-06-17 15:42:30 -04:00
FMeshMaterialShaderElementData ShaderElementData ;
ShaderElementData . InitializeMeshMaterialData ( View , PrimitiveSceneProxy , MeshBatch , - 1 , false ) ;
2018-12-18 21:41:17 -05:00
2020-02-06 13:13:41 -05:00
int32 DataOffset = 0 ;
FMeshDrawSingleShaderBindings SingleShaderBindings = ShaderBindings . GetSingleShaderBindings ( SF_Compute , DataOffset ) ;
2021-04-20 14:31:30 -04:00
FMeshPassProcessorRenderState DrawRenderState ( View - > ViewUniformBuffer ) ;
2019-06-17 15:42:30 -04:00
Shader - > GetShaderBindings ( Scene , Scene - > GetFeatureLevel ( ) , PrimitiveSceneProxy , MaterialRenderProxy , Material , DrawRenderState , ShaderElementData , SingleShaderBindings ) ;
2018-12-18 21:41:17 -05:00
2019-06-17 15:42:30 -04:00
FVertexInputStreamArray DummyArray ;
2020-02-06 13:13:41 -05:00
FMeshMaterialShader : : GetElementShaderBindings ( Shader , Scene , View , MeshBatch . VertexFactory , EVertexInputStreamType : : Default , Scene - > GetFeatureLevel ( ) , PrimitiveSceneProxy , MeshBatch , MeshBatch . Elements [ 0 ] , ShaderElementData , SingleShaderBindings , DummyArray ) ;
2018-12-18 21:41:17 -05:00
2020-08-11 01:36:57 -04:00
DispatchCmd . TargetBuffer = RWBuffer ;
2019-06-17 15:42:30 -04:00
DispatchCmd . NumMaxVertices = UpdateParams . NumVertices ;
2020-08-11 01:36:57 -04:00
// Setup the loose parameters directly on the binding
uint32 OutputVertexBaseIndex = VertexBufferOffset / sizeof ( float ) ;
uint32 MinVertexIndex = MeshBatch . Elements [ 0 ] . MinVertexIndex ;
2020-11-24 18:42:39 -04:00
uint32 NumCPUVertices = UpdateParams . NumVertices ;
2019-06-17 15:42:30 -04:00
if ( MeshBatch . Elements [ 0 ] . MinVertexIndex < MeshBatch . Elements [ 0 ] . MaxVertexIndex )
{
2020-11-24 18:42:39 -04:00
NumCPUVertices = 1 + MeshBatch . Elements [ 0 ] . MaxVertexIndex - MeshBatch . Elements [ 0 ] . MinVertexIndex ;
2019-06-17 15:42:30 -04:00
}
2020-08-11 01:36:57 -04:00
2021-05-25 07:27:25 -04:00
const uint32 VertexBufferNumElements = UpdateParams . VertexBufferSize / sizeof ( FVector3f ) - MinVertexIndex ;
2021-01-08 19:56:07 -04:00
if ( ! ensureMsgf ( NumCPUVertices < = VertexBufferNumElements ,
TEXT ( " Vertex buffer contains %d vertices, but RayTracingDynamicGeometryConverterCS dispatch command expects at least %d. " ) ,
VertexBufferNumElements , NumCPUVertices ) )
{
NumCPUVertices = VertexBufferNumElements ;
}
2020-11-24 18:42:39 -04:00
SingleShaderBindings . Add ( Shader - > UsingIndirectDraw , bUsingIndirectDraw ? 1 : 0 ) ;
2020-08-11 01:36:57 -04:00
SingleShaderBindings . Add ( Shader - > NumVertices , NumCPUVertices ) ;
SingleShaderBindings . Add ( Shader - > MinVertexIndex , MinVertexIndex ) ;
SingleShaderBindings . Add ( Shader - > PrimitiveId , PrimitiveId ) ;
SingleShaderBindings . Add ( Shader - > OutputVertexBaseIndex , OutputVertexBaseIndex ) ;
SingleShaderBindings . Add ( Shader - > bApplyWorldPositionOffset , UpdateParams . bApplyWorldPositionOffset ? 1 : 0 ) ;
2022-02-02 05:56:37 -05:00
SingleShaderBindings . Add ( Shader - > InstanceId , UpdateParams . InstanceId ) ;
SingleShaderBindings . Add ( Shader - > WorldToInstance , UpdateParams . WorldToInstance ) ;
2019-06-17 15:42:30 -04:00
# if MESH_DRAW_COMMAND_DEBUG_DATA
FMeshProcessorShaders ShadersForDebug = Shaders . GetUntypedShaders ( ) ;
ShaderBindings . Finalize ( & ShadersForDebug ) ;
# endif
2020-08-11 01:36:57 -04:00
DispatchCommands . Add ( DispatchCmd ) ;
2019-06-17 15:42:30 -04:00
}
2018-12-18 21:41:17 -05:00
2019-06-11 18:27:07 -04:00
bool bRefit = true ;
2020-08-11 01:36:57 -04:00
// Optionally resize the buffer when not shared (could also be lazy allocated and still empty)
if ( ! bUseSharedVertexBuffer & & RWBuffer - > NumBytes ! = UpdateParams . VertexBufferSize )
2018-12-18 21:41:17 -05:00
{
2021-02-16 08:37:39 -04:00
RWBuffer - > Initialize ( TEXT ( " FRayTracingDynamicGeometryCollection::RayTracingDynamicVertexBuffer " ) , sizeof ( float ) , UpdateParams . VertexBufferSize / sizeof ( float ) , PF_R32_FLOAT , BUF_UnorderedAccess | BUF_ShaderResource ) ;
2019-06-11 18:27:07 -04:00
bRefit = false ;
2018-12-18 21:41:17 -05:00
}
2019-06-11 18:27:07 -04:00
if ( ! Geometry . RayTracingGeometryRHI . IsValid ( ) )
{
bRefit = false ;
}
if ( ! Geometry . Initializer . bAllowUpdate )
{
bRefit = false ;
}
2018-12-18 21:41:17 -05:00
check ( Geometry . IsInitialized ( ) ) ;
2019-10-16 15:02:29 -04:00
if ( Geometry . Initializer . TotalPrimitiveCount ! = UpdateParams . NumTriangles )
{
check ( Geometry . Initializer . Segments . Num ( ) < = 1 ) ;
Geometry . Initializer . TotalPrimitiveCount = UpdateParams . NumTriangles ;
Geometry . Initializer . Segments . Empty ( ) ;
FRayTracingGeometrySegment Segment ;
Segment . NumPrimitives = UpdateParams . NumTriangles ;
2021-03-19 07:30:59 -04:00
Segment . MaxVertices = UpdateParams . NumVertices ;
2019-10-16 15:02:29 -04:00
Geometry . Initializer . Segments . Add ( Segment ) ;
bRefit = false ;
}
for ( FRayTracingGeometrySegment & Segment : Geometry . Initializer . Segments )
{
2020-08-11 01:36:57 -04:00
Segment . VertexBuffer = RWBuffer - > Buffer ;
Segment . VertexBufferOffset = VertexBufferOffset ;
2019-10-16 15:02:29 -04:00
}
2019-06-11 18:27:07 -04:00
if ( ! bRefit )
{
2020-09-01 14:07:48 -04:00
checkf ( Geometry . Initializer . OfflineData = = nullptr , TEXT ( " Dynamic geometry is not expected to have offline acceleration structure data " ) ) ;
2019-06-11 18:27:07 -04:00
Geometry . RayTracingGeometryRHI = RHICreateRayTracingGeometry ( Geometry . Initializer ) ;
2021-12-03 09:55:58 -05:00
Geometry . bRequiresBuild = true ;
2019-06-11 18:27:07 -04:00
}
2019-10-16 15:02:29 -04:00
2021-03-31 14:19:03 -04:00
FRayTracingGeometryBuildParams Params ;
2019-10-16 15:02:29 -04:00
Params . Geometry = Geometry . RayTracingGeometryRHI ;
2021-12-03 09:55:58 -05:00
Params . BuildMode = Geometry . bRequiresBuild
? EAccelerationStructureBuildMode : : Build
: EAccelerationStructureBuildMode : : Update ;
Geometry . bRequiresBuild = false ;
2020-08-11 01:36:57 -04:00
if ( bUseSharedVertexBuffer )
{
// Make render thread side temporary copy and move to rhi side allocation when command list is known
// Cache the count of segments so final views can be made when all segments are collected (Segments array could still be reallocated)
Segments . Append ( Geometry . Initializer . Segments ) ;
Params . Segments = MakeArrayView ( ( FRayTracingGeometrySegment * ) nullptr , Geometry . Initializer . Segments . Num ( ) ) ;
}
2019-10-16 15:02:29 -04:00
BuildParams . Add ( Params ) ;
2020-08-11 01:36:57 -04:00
if ( bUseSharedVertexBuffer )
{
Geometry . DynamicGeometrySharedBufferGenerationID = SharedBufferGenerationID ;
}
else
{
Geometry . DynamicGeometrySharedBufferGenerationID = FRayTracingGeometry : : NonSharedVertexBuffers ;
}
2018-12-18 21:41:17 -05:00
}
2021-12-03 09:52:48 -05:00
void FRayTracingDynamicGeometryCollection : : DispatchUpdates ( FRHIComputeCommandList & ParentCmdList , FRHIBuffer * ScratchBuffer )
2018-12-18 21:41:17 -05:00
{
2019-10-01 13:03:04 -04:00
# if WANTS_DRAW_MESH_EVENTS
2021-05-13 13:12:56 -04:00
# define SCOPED_DRAW_OR_COMPUTE_EVENT(ParentCmdList, Name) FDrawEvent PREPROCESSOR_JOIN(Event_##Name,__LINE__); if(GetEmitDrawEvents()) PREPROCESSOR_JOIN(Event_##Name,__LINE__).Start(&ParentCmdList, FColor(0), TEXT(#Name));
2019-10-01 13:03:04 -04:00
# else
# define SCOPED_DRAW_OR_COMPUTE_EVENT(...)
# endif
2020-08-11 01:36:57 -04:00
if ( DispatchCommands . Num ( ) > 0 )
2018-12-18 21:41:17 -05:00
{
2020-08-11 01:36:57 -04:00
SCOPED_DRAW_OR_COMPUTE_EVENT ( ParentCmdList , RayTracingDynamicGeometryUpdate )
2018-12-18 21:41:17 -05:00
{
2019-10-21 10:07:17 -04:00
{
2020-08-11 01:36:57 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SortDispatchCommands ) ;
// This can be optimized by using sorted insert or using map on shaders
// There are only a handful of unique shaders and a few target buffers so we want to swap state as little as possible
// to reduce RHI thread overhead
DispatchCommands . Sort ( [ ] ( const FMeshComputeDispatchCommand & InLHS , const FMeshComputeDispatchCommand & InRHS )
{
if ( InLHS . MaterialShader . GetComputeShader ( ) ! = InRHS . MaterialShader . GetComputeShader ( ) )
return InLHS . MaterialShader . GetComputeShader ( ) < InRHS . MaterialShader . GetComputeShader ( ) ;
return InLHS . TargetBuffer < InRHS . TargetBuffer ;
} ) ;
2019-10-21 10:07:17 -04:00
}
2019-06-11 18:27:07 -04:00
{
2020-08-11 01:36:57 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( SetupSegmentData ) ;
// Setup the array views on final allocated segments array
FRayTracingGeometrySegment * SegmentData = Segments . GetData ( ) ;
2021-03-31 14:19:03 -04:00
for ( FRayTracingGeometryBuildParams & Param : BuildParams )
2019-06-11 18:27:07 -04:00
{
2020-08-11 01:36:57 -04:00
uint32 SegmentCount = Param . Segments . Num ( ) ;
if ( SegmentCount > 0 )
{
Param . Segments = MakeArrayView ( SegmentData , SegmentCount ) ;
SegmentData + = SegmentCount ;
}
2019-06-11 18:27:07 -04:00
}
}
2019-10-21 10:07:17 -04:00
2020-09-24 00:43:27 -04:00
FMemMark Mark ( FMemStack : : Get ( ) ) ;
TArray < FRHITransitionInfo , TMemStackAllocator < > > TransitionsBefore , TransitionsAfter ;
TArray < FRHIUnorderedAccessView * , TMemStackAllocator < > > OverlapUAVs ;
TransitionsBefore . Reserve ( DispatchCommands . Num ( ) ) ;
TransitionsAfter . Reserve ( DispatchCommands . Num ( ) ) ;
OverlapUAVs . Reserve ( DispatchCommands . Num ( ) ) ;
const FRWBuffer * LastBuffer = nullptr ;
2020-08-11 01:36:57 -04:00
for ( FMeshComputeDispatchCommand & Cmd : DispatchCommands )
{
2020-09-24 00:43:27 -04:00
if ( Cmd . TargetBuffer = = nullptr )
{
continue ;
}
2020-08-11 01:36:57 -04:00
FRHIUnorderedAccessView * UAV = Cmd . TargetBuffer - > UAV . GetReference ( ) ;
2020-09-24 00:43:27 -04:00
// The list is sorted by TargetBuffer, so we can remove duplicates by simply looking at the previous value we've processed.
if ( LastBuffer = = Cmd . TargetBuffer )
2020-08-11 01:36:57 -04:00
{
2020-09-24 00:43:27 -04:00
// This UAV is used by more than one dispatch, so tell the RHI it's OK to overlap the dispatches, because
// we're updating disjoint regions.
if ( OverlapUAVs . Num ( ) = = 0 | | OverlapUAVs . Last ( ) ! = UAV )
{
OverlapUAVs . Add ( UAV ) ;
}
continue ;
2020-08-11 01:36:57 -04:00
}
2020-09-24 00:43:27 -04:00
LastBuffer = Cmd . TargetBuffer ;
// Looks like the resource can get here in either UAVCompute or SRVMask mode, so we'll have to use Unknown until we can have better tracking.
TransitionsBefore . Add ( FRHITransitionInfo ( UAV , ERHIAccess : : Unknown , ERHIAccess : : UAVCompute ) ) ;
TransitionsAfter . Add ( FRHITransitionInfo ( UAV , ERHIAccess : : UAVCompute , ERHIAccess : : SRVMask ) ) ;
2020-08-11 01:36:57 -04:00
}
TArray < FRHICommandList * > CommandLists ;
TArray < int32 > CmdListNumDraws ;
TArray < FGraphEventRef > CmdListPrerequisites ;
auto AllocateCommandList = [ & ParentCmdList , & CommandLists , & CmdListNumDraws , & CmdListPrerequisites ]
( uint32 ExpectedNumDraws , TStatId StatId ) - > FRHIComputeCommandList &
{
2021-02-18 18:13:28 -04:00
# if USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
2020-08-11 01:36:57 -04:00
if ( ParentCmdList . Bypass ( ) )
{
return ParentCmdList ;
}
else
{
FRHIComputeCommandList & Result = * CommandLists . Add_GetRef ( new FRHICommandList ( ParentCmdList . GetGPUMask ( ) ) ) ;
Result . ExecuteStat = StatId ;
CmdListNumDraws . Add ( ExpectedNumDraws ) ;
CmdListPrerequisites . AddDefaulted ( ) ;
return Result ;
}
2021-02-18 18:13:28 -04:00
# else // USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
return ParentCmdList ;
# endif // USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
2020-08-11 01:36:57 -04:00
} ;
{
FRHIComputeCommandList & RHICmdList = AllocateCommandList ( DispatchCommands . Num ( ) , GET_STATID ( STAT_CLM_RTDynGeomDispatch ) ) ;
2020-09-24 00:43:27 -04:00
FRHIComputeShader * CurrentShader = nullptr ;
FRWBuffer * CurrentBuffer = nullptr ;
2020-08-11 01:36:57 -04:00
2020-09-24 00:43:27 -04:00
// Transition to writeable for each cmd list and enable UAV overlap, because several dispatches can update non-overlapping portions of the same buffer.
RHICmdList . Transition ( TransitionsBefore ) ;
RHICmdList . BeginUAVOverlap ( OverlapUAVs ) ;
2020-08-11 01:36:57 -04:00
2020-09-24 00:43:27 -04:00
// Cache the bound uniform buffers because a lot are the same between dispatches
FShaderBindingState ShaderBindingState ;
2020-08-11 01:36:57 -04:00
2020-09-24 00:43:27 -04:00
for ( FMeshComputeDispatchCommand & Cmd : DispatchCommands )
2020-08-11 01:36:57 -04:00
{
2020-09-24 00:43:27 -04:00
const TShaderRef < FRayTracingDynamicGeometryConverterCS > & Shader = Cmd . MaterialShader ;
FRHIComputeShader * ComputeShader = Shader . GetComputeShader ( ) ;
if ( CurrentShader ! = ComputeShader )
{
2022-02-08 13:19:37 -05:00
SetComputePipelineState ( RHICmdList , ComputeShader ) ;
2020-09-24 00:43:27 -04:00
CurrentBuffer = nullptr ;
CurrentShader = ComputeShader ;
2020-08-11 01:36:57 -04:00
2020-09-24 00:43:27 -04:00
// Reset binding state
ShaderBindingState = FShaderBindingState ( ) ;
}
FRWBuffer * TargetBuffer = Cmd . TargetBuffer ;
if ( CurrentBuffer ! = TargetBuffer )
{
CurrentBuffer = TargetBuffer ;
Shader - > RWVertexPositions . SetBuffer ( RHICmdList , CurrentShader , * Cmd . TargetBuffer ) ;
}
Cmd . ShaderBindings . SetOnCommandList ( RHICmdList , ComputeShader , & ShaderBindingState ) ;
RHICmdList . DispatchComputeShader ( FMath : : DivideAndRoundUp < uint32 > ( Cmd . NumMaxVertices , 64 ) , 1 , 1 ) ;
2020-08-11 01:36:57 -04:00
}
2020-09-24 00:43:27 -04:00
// Make sure buffers are readable again and disable UAV overlap.
RHICmdList . EndUAVOverlap ( OverlapUAVs ) ;
RHICmdList . Transition ( TransitionsAfter ) ;
2020-08-11 01:36:57 -04:00
}
// Need to kick parallel translate command lists?
if ( CommandLists . Num ( ) > 0 )
{
ParentCmdList . QueueParallelAsyncCommandListSubmit (
CmdListPrerequisites . GetData ( ) , // AnyThreadCompletionEvents
false , // bIsPrepass
CommandLists . GetData ( ) , //CmdLists
CmdListNumDraws . GetData ( ) , // NumDrawsIfKnown
CommandLists . Num ( ) , // Num
0 , // MinDrawsPerTranslate
false // bSpewMerge
) ;
}
2021-01-22 09:52:22 -04:00
if ( BuildParams . Num ( ) > 0 )
{
// Can't use parallel command list because we have to make sure we are not building BVH data
// on the same RTGeometry on multiple threads at the same time. Ideally move the build
// requests over to the RaytracingGeometry manager so they can be correctly scheduled
// with other build requests in the engine (see UE-106982)
SCOPED_DRAW_OR_COMPUTE_EVENT ( ParentCmdList , Build ) ;
2022-01-28 09:41:15 -05:00
FRHIBufferRange ScratchBufferRange ;
ScratchBufferRange . Buffer = ScratchBuffer ;
ScratchBufferRange . Offset = 0 ;
ParentCmdList . BuildAccelerationStructures ( BuildParams , ScratchBufferRange ) ;
2021-01-22 09:52:22 -04:00
}
2020-08-11 01:36:57 -04:00
}
2021-02-18 18:13:28 -04:00
}
2020-08-11 01:36:57 -04:00
# undef SCOPED_DRAW_OR_COMPUTE_EVENT
2018-12-18 21:41:17 -05:00
}
2020-08-11 01:36:57 -04:00
void FRayTracingDynamicGeometryCollection : : EndUpdate ( FRHICommandListImmediate & RHICmdList )
2018-12-18 21:41:17 -05:00
{
2021-04-26 06:23:11 -04:00
ReferencedUniformBuffers . Empty ( ReferencedUniformBuffers . Max ( ) ) ;
2020-08-11 01:36:57 -04:00
// Move ownership to RHI thread for another frame
RHICmdList . EnqueueLambda ( [ ArrayOwnedByRHIThread = MoveTemp ( Segments ) ] ( FRHICommandListImmediate & ) { } ) ;
2018-12-18 21:41:17 -05:00
}
2021-12-03 09:52:48 -05:00
uint32 FRayTracingDynamicGeometryCollection : : ComputeScratchBufferSize ( )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FRayTracingDynamicGeometryCollection : : ComputeScratchBufferSize ) ;
const uint64 ScratchAlignment = GRHIRayTracingAccelerationStructureAlignment ;
uint32 BLASScratchSize = 0 ;
for ( FRayTracingGeometryBuildParams & Params : BuildParams )
{
const FRayTracingAccelerationStructureSize BLASSizeInfo = Params . Geometry - > GetSizeInfo ( ) ;
const uint64 ScratchSize = Params . BuildMode = = EAccelerationStructureBuildMode : : Build ? BLASSizeInfo . BuildScratchSize : BLASSizeInfo . UpdateScratchSize ;
BLASScratchSize = Align ( BLASScratchSize + ScratchSize , ScratchAlignment ) ;
}
return BLASScratchSize ;
}
2021-02-18 18:13:28 -04:00
# undef USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
2018-12-18 21:41:17 -05:00
# endif // RHI_RAYTRACING