2020-12-11 14:21:20 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "RayTracingGeometryManager.h"
# include "RHIResources.h"
# include "RHICommandList.h"
2022-12-02 15:09:41 -05:00
# include "RayTracingGeometry.h"
# include "RenderUtils.h"
2020-12-11 14:21:20 -04:00
# if RHI_RAYTRACING
static int32 GRayTracingMaxBuiltPrimitivesPerFrame = - 1 ;
static FAutoConsoleVariableRef CVarRayTracingMaxBuiltPrimitivesPerFrame (
TEXT ( " r.RayTracing.Geometry.MaxBuiltPrimitivesPerFrame " ) ,
GRayTracingMaxBuiltPrimitivesPerFrame ,
TEXT ( " Sets the ray tracing acceleration structure build budget in terms of maximum number of triangles per frame (<= 0 then disabled and all acceleration structures are build immediatly - default) " ) ,
ECVF_RenderThreadSafe
) ;
static float GRayTracingPendingBuildPriorityBoostPerFrame = 0.001f ;
static FAutoConsoleVariableRef CVarRayTracingPendingBuildPriorityBoostPerFrame (
TEXT ( " r.RayTracing.Geometry.PendingBuildPriorityBoostPerFrame " ) ,
GRayTracingPendingBuildPriorityBoostPerFrame ,
TEXT ( " Increment the priority for all pending build requests which are not scheduled that frame (0.001 - default) " ) ,
ECVF_RenderThreadSafe
) ;
DECLARE_DWORD_ACCUMULATOR_STAT ( TEXT ( " Ray tracing pending builds " ) , STAT_RayTracingPendingBuilds , STATGROUP_SceneRendering ) ;
DECLARE_DWORD_ACCUMULATOR_STAT ( TEXT ( " Ray tracing pending build primitives " ) , STAT_RayTracingPendingBuildPrimitives , STATGROUP_SceneRendering ) ;
FRayTracingGeometryManager GRayTracingGeometryManager ;
static float GetInitialBuildPriority ( ERTAccelerationStructureBuildPriority InBuildPriority )
{
switch ( InBuildPriority )
{
case ERTAccelerationStructureBuildPriority : : Immediate : return 1.0f ;
case ERTAccelerationStructureBuildPriority : : High : return 0.5f ;
case ERTAccelerationStructureBuildPriority : : Normal : return 0.24f ;
case ERTAccelerationStructureBuildPriority : : Low : return 0.01f ;
case ERTAccelerationStructureBuildPriority : : Skip :
default :
{
// should not get here
check ( false ) ;
return 0.0f ;
}
}
}
FRayTracingGeometryManager : : BuildRequestIndex FRayTracingGeometryManager : : RequestBuildAccelerationStructure ( FRayTracingGeometry * InGeometry , ERTAccelerationStructureBuildPriority InPriority , EAccelerationStructureBuildMode InBuildMode )
{
// If immediate then enqueue command directly on the immediate command list
if ( GRayTracingMaxBuiltPrimitivesPerFrame < = 0 | | InPriority = = ERTAccelerationStructureBuildPriority : : Immediate )
{
check ( InBuildMode = = EAccelerationStructureBuildMode : : Build ) ;
FRHICommandListExecutor : : GetImmediateCommandList ( ) . BuildAccelerationStructure ( InGeometry - > RayTracingGeometryRHI ) ;
return INDEX_NONE ;
}
else
{
BuildRequest Request ;
Request . BuildPriority = GetInitialBuildPriority ( InPriority ) ;
Request . Owner = InGeometry ;
Request . BuildMode = EAccelerationStructureBuildMode : : Build ;
FScopeLock ScopeLock ( & RequestCS ) ;
BuildRequestIndex RequestIndex = GeometryBuildRequests . Add ( Request ) ;
GeometryBuildRequests [ RequestIndex ] . RequestIndex = RequestIndex ;
INC_DWORD_STAT ( STAT_RayTracingPendingBuilds ) ;
INC_DWORD_STAT_BY ( STAT_RayTracingPendingBuildPrimitives , InGeometry - > Initializer . TotalPrimitiveCount ) ;
return RequestIndex ;
}
}
void FRayTracingGeometryManager : : RemoveBuildRequest ( BuildRequestIndex InRequestIndex )
{
FScopeLock ScopeLock ( & RequestCS ) ;
DEC_DWORD_STAT ( STAT_RayTracingPendingBuilds ) ;
DEC_DWORD_STAT_BY ( STAT_RayTracingPendingBuildPrimitives , GeometryBuildRequests [ InRequestIndex ] . Owner - > Initializer . TotalPrimitiveCount ) ;
GeometryBuildRequests . RemoveAt ( InRequestIndex ) ;
}
2022-10-19 09:00:41 -04:00
FRayTracingGeometryManager : : RayTracingGeometryHandle FRayTracingGeometryManager : : RegisterRayTracingGeometry ( FRayTracingGeometry * InGeometry )
{
if ( GetRayTracingMode ( ) = = ERayTracingMode : : Dynamic )
{
check ( InGeometry ) ;
FScopeLock ScopeLock ( & RequestCS ) ;
RayTracingGeometryHandle Handle = RegisteredGeometries . Add ( InGeometry ) ;
return Handle ;
}
return INDEX_NONE ;
}
void FRayTracingGeometryManager : : ReleaseRayTracingGeometryHandle ( RayTracingGeometryHandle Handle )
{
if ( GetRayTracingMode ( ) = = ERayTracingMode : : Dynamic )
{
check ( Handle ! = INDEX_NONE ) ;
FScopeLock ScopeLock ( & RequestCS ) ;
RegisteredGeometries . RemoveAt ( Handle ) ;
}
}
2023-04-19 17:50:40 -04:00
void FRayTracingGeometryManager : : Tick ( bool bHasRayTracingEnableChanged )
2022-10-19 09:00:41 -04:00
{
if ( GetRayTracingMode ( ) ! = ERayTracingMode : : Dynamic )
{
return ;
}
2022-11-21 07:24:06 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FRayTracingGeometryManager : : Tick ) ;
QUICK_SCOPE_CYCLE_COUNTER ( STAT_FRayTracingGeometryManager_Tick ) ;
2023-04-19 17:50:40 -04:00
if ( ! bHasRayTracingEnableChanged )
{
// If the code below triggers a check then dynamic ray tracing is not going to work as expected ie. not all memory will be released or we'll be missing geometry.
# if DO_CHECK
if ( IsRayTracingEnabled ( ) )
{
FScopeLock ScopeLock ( & RequestCS ) ;
for ( FRayTracingGeometry * Geometry : RegisteredGeometries )
{
checkf ( Geometry - > RayTracingGeometryRHI ! = nullptr , TEXT ( " Ray tracing geometry should be valid at this point. " ) ) ;
}
}
else
{
FScopeLock ScopeLock ( & RequestCS ) ;
for ( FRayTracingGeometry * Geometry : RegisteredGeometries )
{
checkf ( Geometry - > RayTracingGeometryRHI = = nullptr , TEXT ( " Ray tracing geometry should not be valid at this point " ) ) ;
}
}
# endif
return ;
}
2022-10-19 09:00:41 -04:00
if ( IsRayTracingEnabled ( ) )
{
FScopeLock ScopeLock ( & RequestCS ) ;
for ( FRayTracingGeometry * Geometry : RegisteredGeometries )
{
if ( Geometry - > RayTracingGeometryRHI = = nullptr )
{
2022-11-14 08:48:54 -05:00
Geometry - > InitRHIForDynamicRayTracing ( ) ;
2022-10-19 09:00:41 -04:00
}
}
}
else
{
FScopeLock ScopeLock ( & RequestCS ) ;
for ( FRayTracingGeometry * Geometry : RegisteredGeometries )
{
Geometry - > RemoveBuildRequest ( ) ;
Geometry - > RayTracingGeometryRHI . SafeRelease ( ) ;
}
}
}
2020-12-11 14:21:20 -04:00
void FRayTracingGeometryManager : : BoostPriority ( BuildRequestIndex InRequestIndex , float InBoostValue )
{
FScopeLock ScopeLock ( & RequestCS ) ;
GeometryBuildRequests [ InRequestIndex ] . BuildPriority + = InBoostValue ;
}
2021-03-03 04:56:50 -04:00
void FRayTracingGeometryManager : : ForceBuildIfPending ( FRHIComputeCommandList & InCmdList , const TArrayView < const FRayTracingGeometry * > InGeometries )
2020-12-11 14:21:20 -04:00
{
FScopeLock ScopeLock ( & RequestCS ) ;
BuildParams . Empty ( FMath : : Max ( BuildParams . Max ( ) , InGeometries . Num ( ) ) ) ;
for ( const FRayTracingGeometry * Geometry : InGeometries )
{
2021-03-03 04:56:50 -04:00
if ( Geometry - > HasPendingBuildRequest ( ) )
{
SetupBuildParams ( GeometryBuildRequests [ Geometry - > RayTracingBuildRequestIndex ] , BuildParams ) ;
}
}
if ( BuildParams . Num ( ) )
{
InCmdList . BuildAccelerationStructures ( BuildParams ) ;
2020-12-11 14:21:20 -04:00
}
}
void FRayTracingGeometryManager : : ProcessBuildRequests ( FRHIComputeCommandList & InCmdList , bool bInBuildAll )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FRayTracingGeometryManager : : ProcessBuildRequests ) ;
FScopeLock ScopeLock ( & RequestCS ) ;
if ( GeometryBuildRequests . Num ( ) = = 0 )
{
return ;
}
SortedRequests . Empty ( FMath : : Max ( SortedRequests . Max ( ) , GeometryBuildRequests . Num ( ) ) ) ;
{
TRACE_CPUPROFILER_EVENT_SCOPE ( SortRequests ) ;
// Is there a fast way to extract all entries from sparse array?
for ( const BuildRequest & Request : GeometryBuildRequests )
{
SortedRequests . Add ( Request ) ;
}
SortedRequests . Sort ( [ ] ( const BuildRequest & InLHS , const BuildRequest & InRHS )
{
return InLHS . BuildPriority > InRHS . BuildPriority ;
} ) ;
}
BuildParams . Empty ( FMath : : Max ( BuildParams . Max ( ) , SortedRequests . Num ( ) ) ) ;
// process n requests each 'frame'
uint64 PrimitivesBuild = 0 ;
bool bAddBuildRequest = true ;
for ( BuildRequest & Request : SortedRequests )
{
if ( bAddBuildRequest )
{
SetupBuildParams ( Request , BuildParams ) ;
// Requested enough?
PrimitivesBuild + = Request . Owner - > Initializer . TotalPrimitiveCount ;
if ( ! bInBuildAll & & PrimitivesBuild > GRayTracingMaxBuiltPrimitivesPerFrame )
bAddBuildRequest = false ;
}
else
{
// Increment priority to make sure requests don't starve
Request . BuildPriority + = GRayTracingPendingBuildPriorityBoostPerFrame ;
}
}
// kick actual build request to RHI command list
InCmdList . BuildAccelerationStructures ( BuildParams ) ;
}
2021-03-31 14:19:03 -04:00
void FRayTracingGeometryManager : : SetupBuildParams ( const BuildRequest & InBuildRequest , TArray < FRayTracingGeometryBuildParams > & InBuildParams )
2020-12-11 14:21:20 -04:00
{
// Setup the actual build params
2021-03-31 14:19:03 -04:00
FRayTracingGeometryBuildParams BuildParam ;
2020-12-11 14:21:20 -04:00
BuildParam . Geometry = InBuildRequest . Owner - > RayTracingGeometryRHI ;
BuildParam . BuildMode = InBuildRequest . BuildMode ;
InBuildParams . Add ( BuildParam ) ;
// Remove from pending array and update the geometry that data is valid
check ( InBuildRequest . RequestIndex ! = INDEX_NONE ) ;
GeometryBuildRequests . RemoveAt ( InBuildRequest . RequestIndex ) ;
InBuildRequest . Owner - > RayTracingBuildRequestIndex = INDEX_NONE ;
DEC_DWORD_STAT ( STAT_RayTracingPendingBuilds ) ;
DEC_DWORD_STAT_BY ( STAT_RayTracingPendingBuildPrimitives , InBuildRequest . Owner - > Initializer . TotalPrimitiveCount ) ;
}
# endif // RHI_RAYTRACING