2022-05-24 17:27:36 -04:00
|
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
#include "RayTracingScene.h"
|
|
|
|
|
|
|
|
|
|
#if RHI_RAYTRACING
|
|
|
|
|
|
|
|
|
|
#include "RayTracingInstanceBufferUtil.h"
|
|
|
|
|
#include "RenderCore.h"
|
|
|
|
|
#include "RayTracingDefinitions.h"
|
|
|
|
|
#include "RenderGraphBuilder.h"
|
|
|
|
|
#include "RenderGraphUtils.h"
|
|
|
|
|
|
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FBuildInstanceBufferPassParams, )
|
|
|
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer, InstanceBuffer)
|
|
|
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
|
|
|
|
|
|
FRayTracingScene::FRayTracingScene()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRayTracingScene::~FRayTracingScene()
|
|
|
|
|
{
|
|
|
|
|
WaitForTasks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRayTracingScene::Create(FRDGBuilder& GraphBuilder, const FGPUScene& GPUScene, const FViewMatrices& ViewMatrices)
|
|
|
|
|
{
|
|
|
|
|
QUICK_SCOPE_CYCLE_COUNTER(FRayTracingScene_BeginCreate);
|
|
|
|
|
|
|
|
|
|
// Round up buffer sizes to some multiple to avoid pathological growth reallocations.
|
|
|
|
|
static constexpr uint32 AllocationGranularity = 8 * 1024;
|
|
|
|
|
static constexpr uint64 BufferAllocationGranularity = 16 * 1024 * 1024;
|
|
|
|
|
|
|
|
|
|
WaitForTasks();
|
|
|
|
|
|
|
|
|
|
static const uint8 NumLayers = uint32(ERayTracingSceneLayer::NUM);
|
|
|
|
|
|
|
|
|
|
FRayTracingSceneWithGeometryInstances SceneWithGeometryInstances = CreateRayTracingSceneWithGeometryInstances(
|
|
|
|
|
Instances,
|
|
|
|
|
NumLayers,
|
|
|
|
|
RAY_TRACING_NUM_SHADER_SLOTS,
|
|
|
|
|
RAY_TRACING_NUM_MISS_SHADER_SLOTS,
|
|
|
|
|
NumCallableShaderSlots);
|
|
|
|
|
|
|
|
|
|
RayTracingSceneRHI = SceneWithGeometryInstances.Scene;
|
|
|
|
|
|
|
|
|
|
const FRayTracingSceneInitializer2& SceneInitializer = RayTracingSceneRHI->GetInitializer();
|
|
|
|
|
|
|
|
|
|
const uint32 NumNativeInstances = SceneWithGeometryInstances.NumNativeGPUSceneInstances + SceneWithGeometryInstances.NumNativeGPUInstances + SceneWithGeometryInstances.NumNativeCPUInstances;
|
|
|
|
|
const uint32 NumNativeInstancesAligned = FMath::DivideAndRoundUp(FMath::Max(NumNativeInstances, 1U), AllocationGranularity) * AllocationGranularity;
|
|
|
|
|
const uint32 NumTransformsAligned = FMath::DivideAndRoundUp(FMath::Max(SceneWithGeometryInstances.NumNativeCPUInstances, 1U), AllocationGranularity) * AllocationGranularity;
|
|
|
|
|
|
|
|
|
|
FRayTracingAccelerationStructureSize SizeInfo = RayTracingSceneRHI->GetSizeInfo();
|
|
|
|
|
SizeInfo.ResultSize = FMath::DivideAndRoundUp(FMath::Max(SizeInfo.ResultSize, 1ull), BufferAllocationGranularity) * BufferAllocationGranularity;
|
|
|
|
|
|
|
|
|
|
// Allocate GPU buffer if current one is too small or significantly larger than what we need.
|
|
|
|
|
if (!RayTracingSceneBuffer.IsValid()
|
|
|
|
|
|| SizeInfo.ResultSize > RayTracingSceneBuffer->GetSize()
|
|
|
|
|
|| SizeInfo.ResultSize < RayTracingSceneBuffer->GetSize() / 2)
|
|
|
|
|
{
|
|
|
|
|
FRHIResourceCreateInfo CreateInfo(TEXT("FRayTracingScene::SceneBuffer"));
|
|
|
|
|
RayTracingSceneBuffer = RHICreateBuffer(uint32(SizeInfo.ResultSize), EBufferUsageFlags::AccelerationStructure, 0, ERHIAccess::BVHWrite, CreateInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LayerSRVs.SetNum(NumLayers);
|
|
|
|
|
|
|
|
|
|
for (uint32 LayerIndex = 0; LayerIndex < NumLayers; ++LayerIndex)
|
|
|
|
|
{
|
|
|
|
|
FShaderResourceViewInitializer ViewInitializer(RayTracingSceneBuffer, RayTracingSceneRHI->GetLayerBufferOffset(LayerIndex), 0);
|
|
|
|
|
LayerSRVs[LayerIndex] = RHICreateShaderResourceView(ViewInitializer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const uint64 ScratchAlignment = GRHIRayTracingScratchBufferAlignment;
|
|
|
|
|
FRDGBufferDesc ScratchBufferDesc;
|
|
|
|
|
ScratchBufferDesc.Usage = EBufferUsageFlags::RayTracingScratch | EBufferUsageFlags::StructuredBuffer;
|
|
|
|
|
ScratchBufferDesc.BytesPerElement = uint32(ScratchAlignment);
|
|
|
|
|
ScratchBufferDesc.NumElements = uint32(FMath::DivideAndRoundUp(SizeInfo.BuildScratchSize, ScratchAlignment));
|
|
|
|
|
|
|
|
|
|
BuildScratchBuffer = GraphBuilder.CreateBuffer(ScratchBufferDesc, TEXT("FRayTracingScene::ScratchBuffer"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
FRDGBufferDesc InstanceBufferDesc;
|
|
|
|
|
InstanceBufferDesc.Usage = EBufferUsageFlags::UnorderedAccess | EBufferUsageFlags::ShaderResource | EBufferUsageFlags::StructuredBuffer;
|
|
|
|
|
InstanceBufferDesc.BytesPerElement = GRHIRayTracingInstanceDescriptorSize;
|
|
|
|
|
InstanceBufferDesc.NumElements = NumNativeInstancesAligned;
|
|
|
|
|
|
|
|
|
|
InstanceBuffer = GraphBuilder.CreateBuffer(InstanceBufferDesc, TEXT("FRayTracingScene::InstanceBuffer"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Round to PoT to avoid resizing too often
|
|
|
|
|
const uint32 NumGeometries = FMath::RoundUpToPowerOfTwo(SceneInitializer.ReferencedGeometries.Num());
|
|
|
|
|
const uint32 AccelerationStructureAddressesBufferSize = NumGeometries * sizeof(FRayTracingAccelerationStructureAddress);
|
|
|
|
|
|
|
|
|
|
if (AccelerationStructureAddressesBuffer.NumBytes < AccelerationStructureAddressesBufferSize)
|
|
|
|
|
{
|
|
|
|
|
// Need to pass "BUF_MultiGPUAllocate", as virtual addresses are different per GPU
|
|
|
|
|
AccelerationStructureAddressesBuffer.Initialize(
|
|
|
|
|
TEXT("FRayTracingScene::AccelerationStructureAddressesBuffer"), AccelerationStructureAddressesBufferSize, BUF_Volatile | BUF_MultiGPUAllocate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// Create/resize instance upload buffer (if necessary)
|
|
|
|
|
const uint32 UploadBufferSize = NumNativeInstancesAligned * sizeof(FRayTracingInstanceDescriptorInput);
|
|
|
|
|
|
|
|
|
|
if (!InstanceUploadBuffer.IsValid()
|
|
|
|
|
|| UploadBufferSize > InstanceUploadBuffer->GetSize()
|
|
|
|
|
|| UploadBufferSize < InstanceUploadBuffer->GetSize() / 2)
|
|
|
|
|
{
|
|
|
|
|
FRHIResourceCreateInfo CreateInfo(TEXT("FRayTracingScene::InstanceUploadBuffer"));
|
|
|
|
|
InstanceUploadBuffer = RHICreateStructuredBuffer(sizeof(FRayTracingInstanceDescriptorInput), UploadBufferSize, BUF_ShaderResource | BUF_Volatile, CreateInfo);
|
|
|
|
|
InstanceUploadSRV = RHICreateShaderResourceView(InstanceUploadBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
const uint32 UploadBufferSize = NumTransformsAligned * sizeof(FVector4f) * 3;
|
|
|
|
|
|
|
|
|
|
// Create/resize transform upload buffer (if necessary)
|
|
|
|
|
if (!TransformUploadBuffer.IsValid()
|
|
|
|
|
|| UploadBufferSize > TransformUploadBuffer->GetSize()
|
|
|
|
|
|| UploadBufferSize < TransformUploadBuffer->GetSize() / 2)
|
|
|
|
|
{
|
|
|
|
|
FRHIResourceCreateInfo CreateInfo(TEXT("FRayTracingScene::TransformUploadBuffer"));
|
|
|
|
|
TransformUploadBuffer = RHICreateStructuredBuffer(sizeof(FVector4f), UploadBufferSize, BUF_ShaderResource | BUF_Volatile, CreateInfo);
|
|
|
|
|
TransformUploadSRV = RHICreateShaderResourceView(TransformUploadBuffer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NumNativeInstances > 0)
|
|
|
|
|
{
|
|
|
|
|
const uint32 InstanceUploadBytes = NumNativeInstances * sizeof(FRayTracingInstanceDescriptorInput);
|
|
|
|
|
const uint32 TransformUploadBytes = SceneWithGeometryInstances.NumNativeCPUInstances * 3 * sizeof(FVector4f);
|
|
|
|
|
|
|
|
|
|
FRayTracingInstanceDescriptorInput* InstanceUploadData = (FRayTracingInstanceDescriptorInput*)RHILockBuffer(InstanceUploadBuffer, 0, InstanceUploadBytes, RLM_WriteOnly);
|
|
|
|
|
FVector4f* TransformUploadData = (FVector4f*)RHILockBuffer(TransformUploadBuffer, 0, TransformUploadBytes, RLM_WriteOnly);
|
|
|
|
|
|
|
|
|
|
// Fill instance upload buffer on separate thread since results are only needed in RHI thread
|
|
|
|
|
FillInstanceUploadBufferTask = FFunctionGraphTask::CreateAndDispatchWhenReady(
|
|
|
|
|
[InstanceUploadData = MakeArrayView(InstanceUploadData, NumNativeInstances),
|
|
|
|
|
TransformUploadData = MakeArrayView(TransformUploadData, SceneWithGeometryInstances.NumNativeCPUInstances * 3),
|
|
|
|
|
NumNativeGPUSceneInstances = SceneWithGeometryInstances.NumNativeGPUSceneInstances,
|
|
|
|
|
NumNativeCPUInstances = SceneWithGeometryInstances.NumNativeCPUInstances,
|
|
|
|
|
Instances = MakeArrayView(Instances),
|
|
|
|
|
InstanceGeometryIndices = MoveTemp(SceneWithGeometryInstances.InstanceGeometryIndices),
|
|
|
|
|
BaseUploadBufferOffsets = MoveTemp(SceneWithGeometryInstances.BaseUploadBufferOffsets),
|
|
|
|
|
RayTracingSceneRHI = RayTracingSceneRHI,
|
|
|
|
|
PreViewTranslation = ViewMatrices.GetPreViewTranslation()]()
|
|
|
|
|
{
|
|
|
|
|
FTaskTagScope TaskTagScope(ETaskTag::EParallelRenderingThread);
|
|
|
|
|
FillRayTracingInstanceUploadBuffer(
|
|
|
|
|
RayTracingSceneRHI,
|
|
|
|
|
PreViewTranslation,
|
|
|
|
|
Instances,
|
|
|
|
|
InstanceGeometryIndices,
|
|
|
|
|
BaseUploadBufferOffsets,
|
|
|
|
|
NumNativeGPUSceneInstances,
|
|
|
|
|
NumNativeCPUInstances,
|
|
|
|
|
InstanceUploadData,
|
|
|
|
|
TransformUploadData);
|
|
|
|
|
}, TStatId(), nullptr, ENamedThreads::AnyThread);
|
|
|
|
|
|
|
|
|
|
FBuildInstanceBufferPassParams* PassParams = GraphBuilder.AllocParameters<FBuildInstanceBufferPassParams>();
|
|
|
|
|
PassParams->InstanceBuffer = GraphBuilder.CreateUAV(InstanceBuffer);
|
|
|
|
|
|
|
|
|
|
const FLargeWorldRenderPosition AbsoluteViewOrigin(ViewMatrices.GetViewOrigin());
|
|
|
|
|
const FVector ViewTileOffset = AbsoluteViewOrigin.GetTileOffset();
|
|
|
|
|
|
|
|
|
|
GraphBuilder.AddPass(
|
|
|
|
|
RDG_EVENT_NAME("BuildTLASInstanceBuffer"),
|
|
|
|
|
PassParams,
|
|
|
|
|
ERDGPassFlags::Compute,
|
|
|
|
|
[PassParams,
|
|
|
|
|
this,
|
|
|
|
|
GPUScene = &GPUScene,
|
|
|
|
|
ViewTilePosition = AbsoluteViewOrigin.GetTile(),
|
|
|
|
|
RelativePreViewTranslation = ViewMatrices.GetPreViewTranslation() + ViewTileOffset,
|
|
|
|
|
&SceneInitializer,
|
|
|
|
|
NumNativeGPUSceneInstances = SceneWithGeometryInstances.NumNativeGPUSceneInstances,
|
|
|
|
|
NumNativeCPUInstances = SceneWithGeometryInstances.NumNativeCPUInstances,
|
|
|
|
|
GPUInstances = MoveTemp(SceneWithGeometryInstances.GPUInstances)
|
|
|
|
|
](FRHICommandListImmediate& RHICmdList)
|
|
|
|
|
{
|
|
|
|
|
WaitForTasks();
|
|
|
|
|
RHICmdList.UnlockBuffer(InstanceUploadBuffer);
|
|
|
|
|
RHICmdList.UnlockBuffer(TransformUploadBuffer);
|
|
|
|
|
|
|
|
|
|
// Pull this out here, because command list playback (where the lambda is executed) doesn't update the GPU mask
|
|
|
|
|
FRHIGPUMask IterateGPUMasks = RHICmdList.GetGPUMask();
|
|
|
|
|
|
|
|
|
|
RHICmdList.EnqueueLambda([BufferRHIRef = AccelerationStructureAddressesBuffer.Buffer, &SceneInitializer, IterateGPUMasks](FRHICommandListImmediate& RHICmdList)
|
|
|
|
|
{
|
|
|
|
|
QUICK_SCOPE_CYCLE_COUNTER(GetAccelerationStructuresAddresses);
|
|
|
|
|
|
|
|
|
|
for (uint32 GPUIndex : IterateGPUMasks)
|
|
|
|
|
{
|
|
|
|
|
FRayTracingAccelerationStructureAddress* AddressesPtr = (FRayTracingAccelerationStructureAddress*)RHICmdList.LockBufferMGPU(
|
|
|
|
|
BufferRHIRef,
|
|
|
|
|
GPUIndex,
|
|
|
|
|
0,
|
|
|
|
|
SceneInitializer.ReferencedGeometries.Num() * sizeof(FRayTracingAccelerationStructureAddress), RLM_WriteOnly);
|
|
|
|
|
|
|
|
|
|
const uint32 NumGeometries = SceneInitializer.ReferencedGeometries.Num();
|
|
|
|
|
for (uint32 GeometryIndex = 0; GeometryIndex < NumGeometries; ++GeometryIndex)
|
|
|
|
|
{
|
|
|
|
|
AddressesPtr[GeometryIndex] = SceneInitializer.ReferencedGeometries[GeometryIndex]->GetAccelerationStructureAddress(GPUIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RHICmdList.UnlockBufferMGPU(BufferRHIRef, GPUIndex);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
BuildRayTracingInstanceBuffer(
|
|
|
|
|
RHICmdList,
|
|
|
|
|
GPUScene,
|
|
|
|
|
ViewTilePosition,
|
|
|
|
|
FVector3f(RelativePreViewTranslation),
|
|
|
|
|
PassParams->InstanceBuffer->GetRHI(),
|
|
|
|
|
InstanceUploadSRV,
|
|
|
|
|
AccelerationStructureAddressesBuffer.SRV,
|
|
|
|
|
TransformUploadSRV,
|
|
|
|
|
NumNativeGPUSceneInstances,
|
|
|
|
|
NumNativeCPUInstances,
|
|
|
|
|
GPUInstances);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRayTracingScene::WaitForTasks() const
|
|
|
|
|
{
|
|
|
|
|
if (FillInstanceUploadBufferTask.IsValid())
|
|
|
|
|
{
|
|
|
|
|
QUICK_SCOPE_CYCLE_COUNTER(WaitForRayTracingSceneFillInstanceUploadBuffer);
|
|
|
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(WaitForRayTracingSceneFillInstanceUploadBuffer);
|
|
|
|
|
FTaskGraphInterface::Get().WaitUntilTaskCompletes(FillInstanceUploadBufferTask, ENamedThreads::GetRenderThread_Local());
|
|
|
|
|
|
|
|
|
|
FillInstanceUploadBufferTask = {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FRayTracingScene::IsCreated() const
|
|
|
|
|
{
|
|
|
|
|
return RayTracingSceneRHI.IsValid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRHIRayTracingScene* FRayTracingScene::GetRHIRayTracingScene() const
|
|
|
|
|
{
|
|
|
|
|
return RayTracingSceneRHI.GetReference();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRHIRayTracingScene* FRayTracingScene::GetRHIRayTracingSceneChecked() const
|
|
|
|
|
{
|
|
|
|
|
FRHIRayTracingScene* Result = GetRHIRayTracingScene();
|
|
|
|
|
checkf(Result, TEXT("Ray tracing scene was not created. Perhaps Create() was not called."));
|
|
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRHIBuffer* FRayTracingScene::GetBufferChecked() const
|
|
|
|
|
{
|
|
|
|
|
checkf(RayTracingSceneBuffer.IsValid(), TEXT("Ray tracing scene buffer was not created. Perhaps Create() was not called."));
|
|
|
|
|
return RayTracingSceneBuffer.GetReference();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FRHIShaderResourceView* FRayTracingScene::GetLayerSRVChecked(ERayTracingSceneLayer Layer) const
|
|
|
|
|
{
|
|
|
|
|
checkf(LayerSRVs[uint8(Layer)].IsValid(), TEXT("Ray tracing scene SRV was not created. Perhaps Create() was not called."));
|
|
|
|
|
return LayerSRVs[uint8(Layer)].GetReference();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRayTracingScene::Reset()
|
|
|
|
|
{
|
|
|
|
|
WaitForTasks();
|
|
|
|
|
|
|
|
|
|
Instances.Reset();
|
|
|
|
|
NumCallableShaderSlots = 0;
|
|
|
|
|
CallableCommands.Reset();
|
2022-05-26 05:59:55 -04:00
|
|
|
UniformBuffers.Reset();
|
2022-05-24 17:27:36 -04:00
|
|
|
GeometriesToBuild.Reset();
|
|
|
|
|
UsedCoarseMeshStreamingHandles.Reset();
|
|
|
|
|
|
|
|
|
|
Allocator.Flush();
|
|
|
|
|
|
|
|
|
|
BuildScratchBuffer = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FRayTracingScene::ResetAndReleaseResources()
|
|
|
|
|
{
|
|
|
|
|
Reset();
|
|
|
|
|
|
|
|
|
|
Instances.Empty();
|
|
|
|
|
CallableCommands.Empty();
|
2022-05-26 05:59:55 -04:00
|
|
|
UniformBuffers.Empty();
|
2022-05-24 17:27:36 -04:00
|
|
|
GeometriesToBuild.Empty();
|
|
|
|
|
UsedCoarseMeshStreamingHandles.Empty();
|
|
|
|
|
RayTracingSceneBuffer = nullptr;
|
|
|
|
|
RayTracingSceneRHI = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // RHI_RAYTRACING
|