CelticCraft/Plugins/VoxelFree/Source/Voxel/Private/VoxelShaders/VoxelDistanceFieldShader.cpp

164 lines
6 KiB
C++
Raw Permalink Normal View History

2023-07-03 16:17:13 +00:00
// Copyright 2020 Phyronnaz
#include "VoxelShaders/VoxelDistanceFieldShader.h"
#include "VoxelUtilities/VoxelIntVectorUtilities.h"
#include "ShaderParameterUtils.h"
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FVoxelDistanceFieldParameters, "VoxelDistanceFieldParameters");
FVoxelDistanceFieldBaseCS::FVoxelDistanceFieldBaseCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
: FGlobalShader(Initializer)
{
Src.Bind(Initializer.ParameterMap, TEXT("Src"));
Dst.Bind(Initializer.ParameterMap, TEXT("Dst"));
}
void FVoxelDistanceFieldBaseCS::ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("NUM_THREADS_CS"), VOXEL_DISTANCE_FIELD_NUM_THREADS_CS);
}
void FVoxelDistanceFieldBaseCS::SetBuffers(
FRHICommandList& RHICmdList,
const FRWBuffer& SrcBuffer,
const FRWBuffer& DstBuffer) const
{
Src.SetBuffer(RHICmdList, RHICmdList.GetBoundComputeShader(), SrcBuffer);
Dst.SetBuffer(RHICmdList, RHICmdList.GetBoundComputeShader(), DstBuffer);
}
void FVoxelDistanceFieldBaseCS::SetUniformBuffers(FRHICommandList& RHICmdList, const FVoxelDistanceFieldParameters& Parameters) const
{
const FVoxelDistanceFieldParametersRef ParametersBuffer = FVoxelDistanceFieldParametersRef::CreateUniformBufferImmediate(Parameters, UniformBuffer_MultiFrame);
SetUniformBufferParameter(RHICmdList, RHICmdList.GetBoundComputeShader(), GetUniformBufferParameter<FVoxelDistanceFieldParameters>(), ParametersBuffer);
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
IMPLEMENT_TYPE_LAYOUT(FVoxelDistanceFieldBaseCS)
IMPLEMENT_SHADER_TYPE(, FVoxelJumpFloodCS, TEXT("/Plugin/Voxel/Private/DistanceField.usf"), TEXT("ExpandDistanceField"), SF_Compute);
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FVoxelDistanceFieldShaderHelper::WaitForCompletion() const
{
VOXEL_FUNCTION_COUNTER();
check(IsInGameThread());
Fence.Wait();
}
void FVoxelDistanceFieldShaderHelper::StartCompute(const FIntVector& Size, const TVoxelSharedRef<TArray<FVector3f>>& InOutData, int32 MaxPasses_Debug)
{
VOXEL_FUNCTION_COUNTER();
check(IsInGameThread());
check(InOutData->Num() == Size.X * Size.Y * Size.Z);
check(Size.X > 0 && Size.Y > 0 && Size.Z > 0);
ensure(Fence.IsFenceComplete());
ENQUEUE_RENDER_COMMAND(VoxelDistanceFieldCompute)(
MakeVoxelWeakPtrLambda(this, [=](FRHICommandListImmediate& RHICmdList)
{
Compute_RenderThread(RHICmdList, Size, GetData(*InOutData), GetNum(*InOutData), MaxPasses_Debug);
}));
Fence.BeginFence();
}
void FVoxelDistanceFieldShaderHelper::Compute_RenderThread(
FRHICommandListImmediate& RHICmdList,
const FIntVector& Size,
FVector3f* RESTRICT const Data,
const int32 Num,
int32 MaxPasses_Debug)
{
VOXEL_RENDER_FUNCTION_COUNTER();
check(IsInRenderingThread());
check(Size.X > 0 && Size.Y > 0 && Size.Z > 0);
check(Num == Size.X * Size.Y * Size.Z);
if (AllocatedSize != Size)
{
VOXEL_RENDER_SCOPE_COUNTER("Create Buffers");
AllocatedSize = Size;
SrcBuffer.Initialize(TEXT("DEBUG"), sizeof(float), 3 * Num, PF_R32_FLOAT);
DstBuffer.Initialize(TEXT("DEBUG"), sizeof(float), 3 * Num, PF_R32_FLOAT);
}
{
VOXEL_RENDER_SCOPE_COUNTER("Copy Data To Buffers");
void* BufferData = RHICmdList.LockBuffer(SrcBuffer.Buffer, 0, SrcBuffer.NumBytes, EResourceLockMode::RLM_WriteOnly);
FMemory::Memcpy(BufferData, Data, SrcBuffer.NumBytes);
RHICmdList.UnlockBuffer(SrcBuffer.Buffer);
}
const int32 PowerOfTwo = FMath::CeilLogTwo(Size.GetMax());
for (int32 Pass = 0; Pass < PowerOfTwo; Pass++)
{
if (MaxPasses_Debug == Pass)
{
break;
}
// -1: we want to start with half the size
const int32 Step = 1 << (PowerOfTwo - 1 - Pass);
ApplyComputeShader<FVoxelJumpFloodCS>(RHICmdList, Size, Step);
}
// To copy data
RHICmdList.Transition(FRHITransitionInfo(DstBuffer.UAV, ERHIAccess::Unknown, ERHIAccess::UAVCompute)); // TODO not unknown?
{
VOXEL_RENDER_SCOPE_COUNTER("Copy Data From Buffers");
void* BufferData = RHICmdList.LockBuffer(SrcBuffer.Buffer, 0, SrcBuffer.NumBytes, EResourceLockMode::RLM_ReadOnly);
FMemory::Memcpy(Data, BufferData, SrcBuffer.NumBytes);
RHICmdList.UnlockBuffer(SrcBuffer.Buffer);
}
// Make sure to release the buffers, else will crash on DX12!
SrcBuffer.Release();
DstBuffer.Release();
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template<typename T>
void FVoxelDistanceFieldShaderHelper::ApplyComputeShader(
FRHICommandListImmediate& RHICmdList,
const FIntVector& Size,
int32 Step)
{
check(IsInRenderingThread());
const TShaderMapRef<T> ComputeShader(GetGlobalShaderMap(ERHIFeatureLevel::SM5));
RHICmdList.SetComputeShader(ComputeShader.GetComputeShader());
FVoxelDistanceFieldParameters Parameters;
Parameters.SizeX = Size.X;
Parameters.SizeY = Size.Y;
Parameters.SizeZ = Size.Z;
Parameters.Step = Step;
ComputeShader->SetUniformBuffers(RHICmdList, Parameters);
const FIntVector NumThreads = FVoxelUtilities::DivideCeil(Size, VOXEL_DISTANCE_FIELD_NUM_THREADS_CS);
check(NumThreads.X > 0 && NumThreads.Y > 0 && NumThreads.Z > 0);
RHICmdList.Transition(FRHITransitionInfo(SrcBuffer.UAV, ERHIAccess::UAVCompute, ERHIAccess::UAVCompute));
RHICmdList.Transition(FRHITransitionInfo(DstBuffer.UAV, ERHIAccess::UAVCompute, ERHIAccess::UAVCompute));
ComputeShader->SetBuffers(RHICmdList, SrcBuffer, DstBuffer);
RHICmdList.DispatchComputeShader(NumThreads.X, NumThreads.Y, NumThreads.Z);
Swap(SrcBuffer, DstBuffer);
}