Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/RayTracing/RayTracingDynamicGeometry.cpp
aleksander netzel 76440ccd82 Handle missing shader in FRayTracingDynamicGeometryCollection::AddDynamicMeshBatchForGeometryUpdate:
* If during shader compilation we end up using a fallback material that does not support FRayTracingDynamicGeometryConverterCS we skip that MeshBatch.

#rb Jason.Nadro
#jira UE-143349
#preflight 62169d31c152c67496efb946

#ROBOMERGE-AUTHOR: aleksander.netzel
#ROBOMERGE-SOURCE: CL 19112093 in //UE5/Release-5.0/... via CL 19112145
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v921-19075845)

[CL 19152808 by aleksander netzel in ue5-main branch]
2022-02-25 14:15:54 -05:00

581 lines
23 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MeshMaterialShader.h"
#include "ScenePrivate.h"
#include "RayTracingDynamicGeometryCollection.h"
#include "RayTracingInstance.h"
#if RHI_RAYTRACING
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(
TEXT("r.RayTracing.DynamicGeometry.SharedVertexBufferGarbageCollectLatency"),
GRTDynGeomSharedVertexBufferGarbageCollectLatency,
TEXT("Amount of update cycles before a heap is deleted when not used (default 30)."),
ECVF_RenderThreadSafe
);
DECLARE_CYCLE_STAT(TEXT("RTDynGeomDispatch"), STAT_CLM_RTDynGeomDispatch, STATGROUP_ParallelCommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("RTDynGeomBuild"), STAT_CLM_RTDynGeomBuild, STATGROUP_ParallelCommandListMarkers);
// 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
class FRayTracingDynamicGeometryConverterCS : public FMeshMaterialShader
{
DECLARE_SHADER_TYPE(FRayTracingDynamicGeometryConverterCS, MeshMaterial);
public:
FRayTracingDynamicGeometryConverterCS(const FMeshMaterialShaderType::CompiledShaderInitializerType& Initializer)
: FMeshMaterialShader(Initializer)
{
PassUniformBuffer.Bind(Initializer.ParameterMap, FSceneTextureUniformParameters::StaticStructMetadata.GetShaderVariableName());
RWVertexPositions.Bind(Initializer.ParameterMap, TEXT("VertexPositions"));
UsingIndirectDraw.Bind(Initializer.ParameterMap, TEXT("UsingIndirectDraw"));
NumVertices.Bind(Initializer.ParameterMap, TEXT("NumVertices"));
MinVertexIndex.Bind(Initializer.ParameterMap, TEXT("MinVertexIndex"));
PrimitiveId.Bind(Initializer.ParameterMap, TEXT("PrimitiveId"));
OutputVertexBaseIndex.Bind(Initializer.ParameterMap, TEXT("OutputVertexBaseIndex"));
bApplyWorldPositionOffset.Bind(Initializer.ParameterMap, TEXT("bApplyWorldPositionOffset"));
InstanceId.Bind(Initializer.ParameterMap, TEXT("InstanceId"));
WorldToInstance.Bind(Initializer.ParameterMap, TEXT("WorldToInstance"));
}
FRayTracingDynamicGeometryConverterCS() = default;
static bool ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters)
{
return Parameters.VertexFactoryType->SupportsRayTracingDynamicGeometry() && ShouldCompileRayTracingShadersForProject(Parameters.Platform);
}
static void ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
OutEnvironment.SetDefine(TEXT("SCENE_TEXTURES_DISABLED"), 1);
}
void GetShaderBindings(
const FScene* Scene,
ERHIFeatureLevel::Type FeatureLevel,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
const FMaterialRenderProxy& MaterialRenderProxy,
const FMaterial& Material,
const FMeshPassProcessorRenderState& DrawRenderState,
const FMeshMaterialShaderElementData& ShaderElementData,
FMeshDrawSingleShaderBindings& ShaderBindings) const
{
FMeshMaterialShader::GetShaderBindings(Scene, FeatureLevel, PrimitiveSceneProxy, MaterialRenderProxy, Material, DrawRenderState, ShaderElementData, ShaderBindings);
}
void GetElementShaderBindings(
const FShaderMapPointerTable& PointerTable,
const FScene* Scene,
const FSceneView* ViewIfDynamicMeshCommand,
const FVertexFactory* VertexFactory,
const EVertexInputStreamType InputStreamType,
ERHIFeatureLevel::Type FeatureLevel,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
const FMeshBatch& MeshBatch,
const FMeshBatchElement& BatchElement,
const FMeshMaterialShaderElementData& ShaderElementData,
FMeshDrawSingleShaderBindings& ShaderBindings,
FVertexInputStreamArray& VertexStreams) const
{
FMeshMaterialShader::GetElementShaderBindings(PointerTable, Scene, ViewIfDynamicMeshCommand, VertexFactory, InputStreamType, FeatureLevel, PrimitiveSceneProxy, MeshBatch, BatchElement, ShaderElementData, ShaderBindings, VertexStreams);
}
LAYOUT_FIELD(FRWShaderParameter, RWVertexPositions);
LAYOUT_FIELD(FShaderParameter, UsingIndirectDraw);
LAYOUT_FIELD(FShaderParameter, NumVertices);
LAYOUT_FIELD(FShaderParameter, MinVertexIndex);
LAYOUT_FIELD(FShaderParameter, PrimitiveId);
LAYOUT_FIELD(FShaderParameter, bApplyWorldPositionOffset);
LAYOUT_FIELD(FShaderParameter, OutputVertexBaseIndex);
LAYOUT_FIELD(FShaderParameter, InstanceId);
LAYOUT_FIELD(FShaderParameter, WorldToInstance);
};
IMPLEMENT_MATERIAL_SHADER_TYPE(, FRayTracingDynamicGeometryConverterCS, TEXT("/Engine/Private/RayTracing/RayTracingDynamicMesh.usf"), TEXT("RayTracingDynamicGeometryConverterCS"), SF_Compute);
FRayTracingDynamicGeometryCollection::FRayTracingDynamicGeometryCollection()
{
}
FRayTracingDynamicGeometryCollection::~FRayTracingDynamicGeometryCollection()
{
for (FVertexPositionBuffer* Buffer : VertexPositionBuffers)
{
delete Buffer;
}
VertexPositionBuffers.Empty();
}
int64 FRayTracingDynamicGeometryCollection::BeginUpdate()
{
// 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
// Garbage collect unused buffers for n generations
for (int32 BufferIndex = 0; BufferIndex < VertexPositionBuffers.Num(); ++BufferIndex)
{
FVertexPositionBuffer* Buffer = VertexPositionBuffers[BufferIndex];
Buffer->UsedSize = 0;
if (Buffer->LastUsedGenerationID + GRTDynGeomSharedVertexBufferGarbageCollectLatency <= SharedBufferGenerationID)
{
VertexPositionBuffers.RemoveAtSwap(BufferIndex);
delete Buffer;
BufferIndex--;
}
}
// Increment generation ID used for validation
SharedBufferGenerationID++;
return SharedBufferGenerationID;
}
void FRayTracingDynamicGeometryCollection::AddDynamicMeshBatchForGeometryUpdate(
const FScene* Scene,
const FSceneView* View,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
FRayTracingDynamicGeometryUpdateParams UpdateParams,
uint32 PrimitiveId
)
{
FRayTracingGeometry& Geometry = *UpdateParams.Geometry;
bool bUsingIndirectDraw = UpdateParams.bUsingIndirectDraw;
uint32 NumMaxVertices = UpdateParams.NumVertices;
FRWBuffer* RWBuffer = UpdateParams.Buffer;
uint32 VertexBufferOffset = 0;
bool bUseSharedVertexBuffer = false;
if (ReferencedUniformBuffers.Num() == 0 || ReferencedUniformBuffers.Last() != View->ViewUniformBuffer)
{
// Keep ViewUniformBuffer alive until EndUpdate()
ReferencedUniformBuffers.Add(View->ViewUniformBuffer);
}
// 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);
static const uint32 VertexBufferCacheSize = GRTDynGeomSharedVertexBufferSizeInMB * 1024 * 1024;
uint32 AllocationSize = FMath::Max(VertexBufferCacheSize, UpdateParams.VertexBufferSize);
VertexPositionBuffer->RWBuffer.Initialize(TEXT("FRayTracingDynamicGeometryCollection::RayTracingDynamicVertexBuffer"), sizeof(float), AllocationSize / sizeof(float), PF_R32_FLOAT, BUF_UnorderedAccess | BUF_ShaderResource);
VertexPositionBuffer->UsedSize = 0;
}
// Update the last used generation ID
VertexPositionBuffer->LastUsedGenerationID = SharedBufferGenerationID;
// Get the offset and update used size
VertexBufferOffset = VertexPositionBuffer->UsedSize;
VertexPositionBuffer->UsedSize += UpdateParams.VertexBufferSize;
bUseSharedVertexBuffer = true;
RWBuffer = &VertexPositionBuffer->RWBuffer;
}
for (const FMeshBatch& MeshBatch : UpdateParams.MeshBatches)
{
if (!ensureMsgf(MeshBatch.VertexFactory->GetType()->SupportsRayTracingDynamicGeometry(),
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."),
MeshBatch.VertexFactory->GetType()->GetName(), *PrimitiveSceneProxy->GetOwnerName().ToString()))
{
continue;
}
const FMaterialRenderProxy* FallbackMaterialRenderProxyPtr = nullptr;
const FMaterial& Material = MeshBatch.MaterialRenderProxy->GetMaterialWithFallback(Scene->GetFeatureLevel(), FallbackMaterialRenderProxyPtr);
auto* MaterialInterface = Material.GetMaterialInterface();
const FMaterialRenderProxy& MaterialRenderProxy = FallbackMaterialRenderProxyPtr ? *FallbackMaterialRenderProxyPtr : *MeshBatch.MaterialRenderProxy;
TMeshProcessorShaders<
FMeshMaterialShader,
FMeshMaterialShader,
FMeshMaterialShader,
FMeshMaterialShader,
FRayTracingDynamicGeometryConverterCS> Shaders;
FMeshComputeDispatchCommand DispatchCmd;
FMaterialShaderTypes ShaderTypes;
ShaderTypes.AddShaderType<FRayTracingDynamicGeometryConverterCS>();
FMaterialShaders MaterialShaders;
if (!Material.TryGetShaders(ShaderTypes, MeshBatch.VertexFactory->GetType(), MaterialShaders))
{
continue;
}
TShaderRef<FRayTracingDynamicGeometryConverterCS> Shader;
MaterialShaders.TryGetShader(SF_Compute, Shader);
DispatchCmd.MaterialShader = Shader;
FMeshDrawShaderBindings& ShaderBindings = DispatchCmd.ShaderBindings;
Shaders.ComputeShader = Shader;
ShaderBindings.Initialize(Shaders.GetUntypedShaders());
FMeshMaterialShaderElementData ShaderElementData;
ShaderElementData.InitializeMeshMaterialData(View, PrimitiveSceneProxy, MeshBatch, -1, false);
int32 DataOffset = 0;
FMeshDrawSingleShaderBindings SingleShaderBindings = ShaderBindings.GetSingleShaderBindings(SF_Compute, DataOffset);
FMeshPassProcessorRenderState DrawRenderState(View->ViewUniformBuffer);
Shader->GetShaderBindings(Scene, Scene->GetFeatureLevel(), PrimitiveSceneProxy, MaterialRenderProxy, Material, DrawRenderState, ShaderElementData, SingleShaderBindings);
FVertexInputStreamArray DummyArray;
FMeshMaterialShader::GetElementShaderBindings(Shader, Scene, View, MeshBatch.VertexFactory, EVertexInputStreamType::Default, Scene->GetFeatureLevel(), PrimitiveSceneProxy, MeshBatch, MeshBatch.Elements[0], ShaderElementData, SingleShaderBindings, DummyArray);
DispatchCmd.TargetBuffer = RWBuffer;
DispatchCmd.NumMaxVertices = UpdateParams.NumVertices;
// Setup the loose parameters directly on the binding
uint32 OutputVertexBaseIndex = VertexBufferOffset / sizeof(float);
uint32 MinVertexIndex = MeshBatch.Elements[0].MinVertexIndex;
uint32 NumCPUVertices = UpdateParams.NumVertices;
if (MeshBatch.Elements[0].MinVertexIndex < MeshBatch.Elements[0].MaxVertexIndex)
{
NumCPUVertices = 1 + MeshBatch.Elements[0].MaxVertexIndex - MeshBatch.Elements[0].MinVertexIndex;
}
const uint32 VertexBufferNumElements = UpdateParams.VertexBufferSize / sizeof(FVector3f) - MinVertexIndex;
if (!ensureMsgf(NumCPUVertices <= VertexBufferNumElements,
TEXT("Vertex buffer contains %d vertices, but RayTracingDynamicGeometryConverterCS dispatch command expects at least %d."),
VertexBufferNumElements, NumCPUVertices))
{
NumCPUVertices = VertexBufferNumElements;
}
SingleShaderBindings.Add(Shader->UsingIndirectDraw, bUsingIndirectDraw ? 1 : 0);
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);
SingleShaderBindings.Add(Shader->InstanceId, UpdateParams.InstanceId);
SingleShaderBindings.Add(Shader->WorldToInstance, UpdateParams.WorldToInstance);
#if MESH_DRAW_COMMAND_DEBUG_DATA
FMeshProcessorShaders ShadersForDebug = Shaders.GetUntypedShaders();
ShaderBindings.Finalize(&ShadersForDebug);
#endif
DispatchCommands.Add(DispatchCmd);
}
bool bRefit = true;
// Optionally resize the buffer when not shared (could also be lazy allocated and still empty)
if (!bUseSharedVertexBuffer && RWBuffer->NumBytes != UpdateParams.VertexBufferSize)
{
RWBuffer->Initialize(TEXT("FRayTracingDynamicGeometryCollection::RayTracingDynamicVertexBuffer"), sizeof(float), UpdateParams.VertexBufferSize / sizeof(float), PF_R32_FLOAT, BUF_UnorderedAccess | BUF_ShaderResource);
bRefit = false;
}
if (!Geometry.RayTracingGeometryRHI.IsValid())
{
bRefit = false;
}
if (!Geometry.Initializer.bAllowUpdate)
{
bRefit = false;
}
check(Geometry.IsInitialized());
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;
Segment.MaxVertices = UpdateParams.NumVertices;
Geometry.Initializer.Segments.Add(Segment);
bRefit = false;
}
for (FRayTracingGeometrySegment& Segment : Geometry.Initializer.Segments)
{
Segment.VertexBuffer = RWBuffer->Buffer;
Segment.VertexBufferOffset = VertexBufferOffset;
}
if (!bRefit)
{
checkf(Geometry.Initializer.OfflineData == nullptr, TEXT("Dynamic geometry is not expected to have offline acceleration structure data"));
Geometry.RayTracingGeometryRHI = RHICreateRayTracingGeometry(Geometry.Initializer);
Geometry.bRequiresBuild = true;
}
FRayTracingGeometryBuildParams Params;
Params.Geometry = Geometry.RayTracingGeometryRHI;
Params.BuildMode = Geometry.bRequiresBuild
? EAccelerationStructureBuildMode::Build
: EAccelerationStructureBuildMode::Update;
Geometry.bRequiresBuild = false;
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());
}
BuildParams.Add(Params);
if (bUseSharedVertexBuffer)
{
Geometry.DynamicGeometrySharedBufferGenerationID = SharedBufferGenerationID;
}
else
{
Geometry.DynamicGeometrySharedBufferGenerationID = FRayTracingGeometry::NonSharedVertexBuffers;
}
}
void FRayTracingDynamicGeometryCollection::DispatchUpdates(FRHIComputeCommandList& ParentCmdList, FRHIBuffer* ScratchBuffer)
{
#if WANTS_DRAW_MESH_EVENTS
#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));
#else
#define SCOPED_DRAW_OR_COMPUTE_EVENT(...)
#endif
if (DispatchCommands.Num() > 0)
{
SCOPED_DRAW_OR_COMPUTE_EVENT(ParentCmdList, RayTracingDynamicGeometryUpdate)
{
{
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;
});
}
{
TRACE_CPUPROFILER_EVENT_SCOPE(SetupSegmentData);
// Setup the array views on final allocated segments array
FRayTracingGeometrySegment* SegmentData = Segments.GetData();
for (FRayTracingGeometryBuildParams& Param : BuildParams)
{
uint32 SegmentCount = Param.Segments.Num();
if (SegmentCount > 0)
{
Param.Segments = MakeArrayView(SegmentData, SegmentCount);
SegmentData += SegmentCount;
}
}
}
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;
for (FMeshComputeDispatchCommand& Cmd : DispatchCommands)
{
if (Cmd.TargetBuffer == nullptr)
{
continue;
}
FRHIUnorderedAccessView* UAV = Cmd.TargetBuffer->UAV.GetReference();
// 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)
{
// 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;
}
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));
}
TArray<FRHICommandList*> CommandLists;
TArray<int32> CmdListNumDraws;
TArray<FGraphEventRef> CmdListPrerequisites;
auto AllocateCommandList = [&ParentCmdList, &CommandLists, &CmdListNumDraws, &CmdListPrerequisites]
(uint32 ExpectedNumDraws, TStatId StatId)->FRHIComputeCommandList&
{
#if USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
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;
}
#else // USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
return ParentCmdList;
#endif // USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
};
{
FRHIComputeCommandList& RHICmdList = AllocateCommandList(DispatchCommands.Num(), GET_STATID(STAT_CLM_RTDynGeomDispatch));
FRHIComputeShader* CurrentShader = nullptr;
FRWBuffer* CurrentBuffer = nullptr;
// 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);
// Cache the bound uniform buffers because a lot are the same between dispatches
FShaderBindingState ShaderBindingState;
for (FMeshComputeDispatchCommand& Cmd : DispatchCommands)
{
const TShaderRef<FRayTracingDynamicGeometryConverterCS>& Shader = Cmd.MaterialShader;
FRHIComputeShader* ComputeShader = Shader.GetComputeShader();
if (CurrentShader != ComputeShader)
{
SetComputePipelineState(RHICmdList, ComputeShader);
CurrentBuffer = nullptr;
CurrentShader = ComputeShader;
// 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);
}
// Make sure buffers are readable again and disable UAV overlap.
RHICmdList.EndUAVOverlap(OverlapUAVs);
RHICmdList.Transition(TransitionsAfter);
}
// 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
);
}
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);
FRHIBufferRange ScratchBufferRange;
ScratchBufferRange.Buffer = ScratchBuffer;
ScratchBufferRange.Offset = 0;
ParentCmdList.BuildAccelerationStructures(BuildParams, ScratchBufferRange);
}
}
}
#undef SCOPED_DRAW_OR_COMPUTE_EVENT
}
void FRayTracingDynamicGeometryCollection::EndUpdate(FRHICommandListImmediate& RHICmdList)
{
ReferencedUniformBuffers.Empty(ReferencedUniformBuffers.Max());
// Move ownership to RHI thread for another frame
RHICmdList.EnqueueLambda([ArrayOwnedByRHIThread = MoveTemp(Segments)](FRHICommandListImmediate&){});
}
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;
}
#undef USE_RAY_TRACING_DYNAMIC_GEOMETRY_PARALLEL_COMMAND_LISTS
#endif // RHI_RAYTRACING