2022-12-02 15:09:41 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "RayTracingGeometry.h"
2023-06-01 18:13:20 -04:00
# include "RHICommandList.h"
2023-01-27 14:17:39 -05:00
# include "HAL/IConsoleManager.h"
2023-11-16 11:28:36 -05:00
# include "RayTracingGeometryManagerInterface.h"
2022-12-02 15:09:41 -05:00
# include "RenderUtils.h"
2024-02-13 05:28:36 -05:00
# include "RHIResourceReplace.h"
2023-01-27 14:54:10 -05:00
# include "RHITextureReference.h" // IWYU pragma: keep
2022-12-02 15:09:41 -05:00
2023-11-16 11:28:36 -05:00
# if RHI_RAYTRACING
IRayTracingGeometryManager * GRayTracingGeometryManager = nullptr ;
# endif
2023-08-31 17:40:48 -04:00
static TAutoConsoleVariable < int32 > CVarDebugForceRuntimeBLAS (
2022-12-02 15:09:41 -05:00
TEXT ( " r.Raytracing.DebugForceRuntimeBLAS " ) ,
2023-08-31 17:40:48 -04:00
0 ,
2022-12-02 15:09:41 -05:00
TEXT ( " Force building BLAS at runtime. " ) ,
ECVF_ReadOnly ) ;
2024-02-27 11:57:07 -05:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // Remove this in UE 5.6 once RayTracingGeometryRHI is made private
2022-12-02 15:09:41 -05:00
# if RHI_RAYTRACING
2024-02-13 05:28:36 -05:00
void FRayTracingGeometry : : InitRHIForStreaming ( FRHIRayTracingGeometry * IntermediateGeometry , FRHIResourceReplaceBatcher & Batcher )
2022-12-07 00:05:42 -05:00
{
2023-10-17 11:52:48 -04:00
ensureMsgf ( RayTracingGeometryRHI | | ! IsRayTracingEnabled ( ) ,
TEXT ( " RayTracingGeometryRHI should be valid when ray tracing is enabled. \n " )
TEXT ( " This check failing points to a race condition between FRayTracingGeometryManager::Tick(...) and FStaticMeshStreamIn processing. \n " )
) ;
Initializer . Type = ERayTracingGeometryInitializerType : : Rendering ;
2022-12-07 00:05:42 -05:00
EnumAddFlags ( GeometryState , EGeometryStateFlags : : StreamedIn ) ;
if ( RayTracingGeometryRHI & & IntermediateGeometry )
{
2024-02-13 05:28:36 -05:00
Batcher . EnqueueReplace ( RayTracingGeometryRHI , IntermediateGeometry ) ;
2022-12-07 00:05:42 -05:00
EnumAddFlags ( GeometryState , EGeometryStateFlags : : Valid ) ;
}
2023-10-17 11:52:48 -04:00
else
{
check ( GetRayTracingMode ( ) = = ERayTracingMode : : Dynamic ) ;
}
2022-12-07 00:05:42 -05:00
}
2024-02-13 05:28:36 -05:00
void FRayTracingGeometry : : ReleaseRHIForStreaming ( FRHIResourceReplaceBatcher & Batcher )
2022-12-07 00:05:42 -05:00
{
2023-09-19 14:34:30 -04:00
RemoveBuildRequest ( ) ;
2022-12-07 00:05:42 -05:00
EnumRemoveFlags ( GeometryState , EGeometryStateFlags : : StreamedIn ) ;
2023-09-19 14:34:30 -04:00
EnumRemoveFlags ( GeometryState , EGeometryStateFlags : : Valid ) ;
2022-12-07 00:05:42 -05:00
2023-10-17 11:52:48 -04:00
Initializer . Type = ERayTracingGeometryInitializerType : : StreamingDestination ;
2022-12-07 00:05:42 -05:00
if ( RayTracingGeometryRHI )
{
2024-02-13 05:28:36 -05:00
Batcher . EnqueueReplace ( RayTracingGeometryRHI , nullptr ) ;
2022-12-07 00:05:42 -05:00
}
}
2023-11-29 17:09:38 -05:00
void FRayTracingGeometry : : RequestBuildIfNeeded ( ERTAccelerationStructureBuildPriority InBuildPriority )
2022-12-02 15:09:41 -05:00
{
RayTracingGeometryRHI - > SetInitializer ( Initializer ) ;
if ( GetRequiresBuild ( ) )
{
2023-11-29 17:09:38 -05:00
RayTracingBuildRequestIndex = GRayTracingGeometryManager - > RequestBuildAccelerationStructure ( this , InBuildPriority ) ;
2022-12-02 15:09:41 -05:00
SetRequiresBuild ( false ) ;
}
}
2023-10-18 14:26:10 -04:00
void FRayTracingGeometry : : MakeResident ( FRHICommandList & RHICmdList )
2022-12-02 15:09:41 -05:00
{
2023-10-18 14:26:10 -04:00
check ( EnumHasAllFlags ( GeometryState , EGeometryStateFlags : : Evicted ) & & RayTracingGeometryRHI = = nullptr ) ;
EnumRemoveFlags ( GeometryState , EGeometryStateFlags : : Evicted ) ;
2022-12-02 15:09:41 -05:00
// Streaming BLAS needs special handling to not get their "streaming" type wiped out as it will cause issues down the line.
// We only have to do this if the geometry was marked to be streamed in.
// In that case we will recreate the geometry as-if it was streamed in.
if ( EnumHasAnyFlags ( GeometryState , FRayTracingGeometry : : EGeometryStateFlags : : StreamedIn ) )
{
// When a mesh is streamed in (FStaticMeshStreamIn::DoFinishUpdate) we update the geometry initializer using just streamed in VB/IB.
// That initializer sets a Rendering type but RHI object was created as StreamingDestination and we have a mismatch between geometry initializer and RHI initializer.
// It's not an issue unless we try to initialize the geometry again using the geometry's initializer.
// We need the current geometry and RHI object to be StreamingDestination so the streaming continues to work.
Initializer . Type = ERayTracingGeometryInitializerType : : StreamingDestination ;
// Creating RHI with StreamingDestination type will only initialize RHI object but will not created the underlying BLAS buffers.
2023-06-19 13:56:56 -04:00
InitRHI ( RHICmdList ) ;
2022-12-02 15:09:41 -05:00
// Here we simulate geometry streaming: create geometry with StreamingSource type to allocate BLAS buffers (1) and swap it with the current geometry (2).
// Follows the same pattern as: (1) FStaticMeshStreamIn::CreateBuffers_* (2) FStaticMeshStreamIn::DoFinishUpdate
// There is no other way to initialize BLAS buffers for the geometry that has a StreamingDestination type.
{
2024-02-13 05:28:36 -05:00
FRHIResourceReplaceBatcher Batcher ( RHICmdList , 1 ) ;
2022-12-02 15:09:41 -05:00
FRayTracingGeometryInitializer IntermediateInitializer = Initializer ;
IntermediateInitializer . Type = ERayTracingGeometryInitializerType : : StreamingSource ;
2023-06-23 16:03:17 -04:00
FRayTracingGeometryRHIRef IntermediateRayTracingGeometry = RHICmdList . CreateRayTracingGeometry ( IntermediateInitializer ) ;
2022-12-02 15:09:41 -05:00
InitRHIForStreaming ( IntermediateRayTracingGeometry , Batcher ) ;
// When Batcher goes out of scope it will add commands to copy the BLAS buffers on RHI thread.
// We need to do it before we build the current geometry (also on RHI thread).
}
2023-11-29 17:09:38 -05:00
RequestBuildIfNeeded ( ERTAccelerationStructureBuildPriority : : Normal ) ;
2022-12-02 15:09:41 -05:00
}
else
{
2023-06-19 13:56:56 -04:00
InitRHI ( RHICmdList ) ;
2022-12-02 15:09:41 -05:00
}
}
2023-09-15 15:31:24 -04:00
void FRayTracingGeometry : : Evict ( )
{
2023-10-18 14:26:10 -04:00
check ( ! EnumHasAllFlags ( GeometryState , EGeometryStateFlags : : Evicted ) & & RayTracingGeometryRHI ! = nullptr ) ;
2023-09-15 15:31:24 -04:00
RemoveBuildRequest ( ) ;
RayTracingGeometryRHI . SafeRelease ( ) ;
2023-10-18 14:26:10 -04:00
EnumAddFlags ( GeometryState , EGeometryStateFlags : : Evicted ) ;
2023-09-15 15:31:24 -04:00
}
2023-11-29 17:09:38 -05:00
void FRayTracingGeometry : : CreateRayTracingGeometry ( FRHICommandListBase & RHICmdList , ERTAccelerationStructureBuildPriority InBuildPriority )
2022-12-02 15:09:41 -05:00
{
// Release previous RHI object if any
ReleaseRHI ( ) ;
if ( RawData . Num ( ) )
{
2023-08-31 17:40:48 -04:00
check ( Initializer . OfflineData = = nullptr ) ;
2022-12-02 15:09:41 -05:00
Initializer . OfflineData = & RawData ;
}
2023-08-31 17:40:48 -04:00
if ( CVarDebugForceRuntimeBLAS . GetValueOnAnyThread ( ) & & Initializer . OfflineData ! = nullptr )
2022-12-02 15:09:41 -05:00
{
Initializer . OfflineData - > Discard ( ) ;
Initializer . OfflineData = nullptr ;
}
bool bAllSegmentsAreValid = Initializer . Segments . Num ( ) > 0 | | Initializer . OfflineData ;
for ( const FRayTracingGeometrySegment & Segment : Initializer . Segments )
{
if ( ! Segment . VertexBuffer )
{
bAllSegmentsAreValid = false ;
break ;
}
}
if ( bAllSegmentsAreValid )
{
2023-09-21 11:59:18 -04:00
// Geometries with StreamingDestination type are initially created in invalid state until they are streamed in (see InitRHIForStreaming).
const bool bWithNativeResource = Initializer . Type ! = ERayTracingGeometryInitializerType : : StreamingDestination ;
if ( bWithNativeResource )
2022-12-02 15:09:41 -05:00
{
EnumAddFlags ( GeometryState , EGeometryStateFlags : : Valid ) ;
}
if ( IsRayTracingEnabled ( ) )
{
2023-06-19 13:56:56 -04:00
RayTracingGeometryRHI = RHICmdList . CreateRayTracingGeometry ( Initializer ) ;
2022-12-02 15:09:41 -05:00
}
2023-10-18 14:26:10 -04:00
else
{
EnumAddFlags ( GeometryState , EGeometryStateFlags : : Evicted ) ;
}
2022-12-02 15:09:41 -05:00
if ( Initializer . OfflineData = = nullptr )
{
// Request build if not skip
if ( InBuildPriority ! = ERTAccelerationStructureBuildPriority : : Skip )
{
2023-10-18 14:26:10 -04:00
if ( RayTracingGeometryRHI )
2022-12-02 15:09:41 -05:00
{
2023-11-29 17:09:38 -05:00
RayTracingBuildRequestIndex = GRayTracingGeometryManager - > RequestBuildAccelerationStructure ( this , InBuildPriority ) ;
2022-12-02 15:09:41 -05:00
}
SetRequiresBuild ( false ) ;
}
else
{
SetRequiresBuild ( true ) ;
}
}
else
{
2023-07-24 20:01:35 -04:00
if ( RayTracingGeometryRHI & & RayTracingGeometryRHI - > IsCompressed ( ) )
{
2023-11-29 17:09:38 -05:00
RayTracingBuildRequestIndex = GRayTracingGeometryManager - > RequestBuildAccelerationStructure ( this , InBuildPriority ) ;
2023-07-24 20:01:35 -04:00
}
2022-12-02 15:09:41 -05:00
SetRequiresBuild ( false ) ;
// Offline data ownership is transferred to the RHI, which discards it after use.
// It is no longer valid to use it after this point.
Initializer . OfflineData = nullptr ;
}
}
}
bool FRayTracingGeometry : : IsValid ( ) const
{
2023-10-18 14:26:10 -04:00
// can't check IsInitialized() because current implementation of hair ray tracing support doesn't initialize resource
//check(IsInitialized());
const bool bIsValidAndNotEvicted = EnumHasAllFlags ( GeometryState , EGeometryStateFlags : : Valid ) & & ! EnumHasAllFlags ( GeometryState , EGeometryStateFlags : : Evicted ) ;
if ( bIsValidAndNotEvicted )
{
check ( RayTracingGeometryRHI ! = nullptr & & Initializer . TotalPrimitiveCount > 0 ) ;
}
return bIsValidAndNotEvicted ;
}
bool FRayTracingGeometry : : IsEvicted ( ) const
{
// can't check IsInitialized() because current implementation of hair ray tracing support doesn't initialize resource
//check(IsInitialized());
const bool bIsEvicted = EnumHasAllFlags ( GeometryState , EGeometryStateFlags : : Evicted ) ;
if ( bIsEvicted )
{
check ( RayTracingGeometryRHI = = nullptr ) ;
}
return bIsEvicted ;
2022-12-02 15:09:41 -05:00
}
2023-06-19 13:56:56 -04:00
void FRayTracingGeometry : : InitRHI ( FRHICommandListBase & RHICmdList )
2022-12-02 15:09:41 -05:00
{
if ( ! IsRayTracingAllowed ( ) )
return ;
ERTAccelerationStructureBuildPriority BuildPriority = Initializer . Type ! = ERayTracingGeometryInitializerType : : Rendering
? ERTAccelerationStructureBuildPriority : : Skip
: ERTAccelerationStructureBuildPriority : : Normal ;
2023-11-29 17:09:38 -05:00
CreateRayTracingGeometry ( RHICmdList , BuildPriority ) ;
2022-12-02 15:09:41 -05:00
}
void FRayTracingGeometry : : ReleaseRHI ( )
{
RemoveBuildRequest ( ) ;
RayTracingGeometryRHI . SafeRelease ( ) ;
2023-09-21 11:59:18 -04:00
GeometryState = EGeometryStateFlags : : Invalid ;
2022-12-02 15:09:41 -05:00
}
void FRayTracingGeometry : : RemoveBuildRequest ( )
{
if ( HasPendingBuildRequest ( ) )
{
2023-11-16 11:28:36 -05:00
GRayTracingGeometryManager - > RemoveBuildRequest ( RayTracingBuildRequestIndex ) ;
2022-12-02 15:09:41 -05:00
RayTracingBuildRequestIndex = INDEX_NONE ;
}
}
2023-09-04 13:55:57 -04:00
void FRayTracingGeometry : : InitResource ( FRHICommandListBase & RHICmdList )
{
2023-09-15 12:02:44 -04:00
ensureMsgf ( IsRayTracingAllowed ( ) , TEXT ( " FRayTracingGeometry should only be initialized when Ray Tracing is allowed. " ) ) ;
2023-09-04 13:55:57 -04:00
FRenderResource : : InitResource ( RHICmdList ) ;
2023-09-14 14:36:39 -04:00
2023-09-15 12:02:44 -04:00
if ( RayTracingGeometryHandle = = INDEX_NONE )
{
2023-11-16 11:28:36 -05:00
RayTracingGeometryHandle = GRayTracingGeometryManager - > RegisterRayTracingGeometry ( this ) ;
2023-09-15 12:02:44 -04:00
}
2023-09-04 13:55:57 -04:00
}
2022-12-02 15:09:41 -05:00
void FRayTracingGeometry : : ReleaseResource ( )
{
2023-09-15 12:02:44 -04:00
ensureMsgf ( IsRayTracingAllowed ( ) | | ! IsInitialized ( ) , TEXT ( " FRayTracingGeometry should only be initialized when Ray Tracing is allowed. " ) ) ;
2023-09-04 13:55:57 -04:00
2023-09-14 14:36:39 -04:00
if ( RayTracingGeometryHandle ! = INDEX_NONE )
{
2023-11-16 11:28:36 -05:00
GRayTracingGeometryManager - > ReleaseRayTracingGeometryHandle ( RayTracingGeometryHandle ) ;
2023-09-14 14:36:39 -04:00
RayTracingGeometryHandle = INDEX_NONE ;
}
2022-12-02 15:09:41 -05:00
// Release any resource references held by the initializer.
// This includes index and vertex buffers used for building the BLAS.
Initializer = FRayTracingGeometryInitializer { } ;
FRenderResource : : ReleaseResource ( ) ;
}
void FRayTracingGeometry : : BoostBuildPriority ( float InBoostValue ) const
{
check ( HasPendingBuildRequest ( ) ) ;
2023-11-16 11:28:36 -05:00
GRayTracingGeometryManager - > BoostPriority ( RayTracingBuildRequestIndex , InBoostValue ) ;
2022-12-02 15:09:41 -05:00
}
# endif // RHI_RAYTRACING
2024-02-27 11:57:07 -05:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS