You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Adaptive ray counts for SMRT now work even with pass per light - Removes a few divergences between the logic in the two paths Remove debug projection stuff for now; will reimplement with a separate UAV write later Remove temporal filtering for denoiser (it was broken and would need to be implemented slightly differently with the new path anyways) Split cvar to allow separate denoiser toggle for directional (default on) and local (default off) lights Enable SMRT for local lights and VSM caching by default #rb brian.karis #ROBOMERGE-OWNER: andrew.lauritzen #ROBOMERGE-AUTHOR: andrew.lauritzen #ROBOMERGE-SOURCE: CL 15707229 in //UE5/Release-5.0-EarlyAccess/... #ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v781-15675533) #ROBOMERGE-CONFLICT from-shelf [CL 15708180 by andrew lauritzen in ue5-main branch]
522 lines
21 KiB
C++
522 lines
21 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
VirtualShadowMap.h:
|
|
=============================================================================*/
|
|
#include "VirtualShadowMapCacheManager.h"
|
|
#include "RendererModule.h"
|
|
#include "RenderGraphUtils.h"
|
|
#include "RHIGPUReadback.h"
|
|
#include "ScenePrivate.h"
|
|
#include "HAL/FileManager.h"
|
|
|
|
#include "PrimitiveSceneInfo.h"
|
|
|
|
static TAutoConsoleVariable<int32> CVarAccumulateStats(
|
|
TEXT("r.Shadow.Virtual.AccumulateStats"),
|
|
0,
|
|
TEXT("AccumulateStats"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
|
|
static TAutoConsoleVariable<int32> CVarCacheVirtualSMs(
|
|
TEXT("r.Shadow.Virtual.Cache"),
|
|
1,
|
|
TEXT("Turn on to enable caching"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
|
|
void FVirtualShadowMapCacheEntry::UpdateClipmap(
|
|
int32 VirtualShadowMapId,
|
|
const FMatrix &WorldToLight,
|
|
FIntPoint PageSpaceLocation,
|
|
float GlobalDepth)
|
|
{
|
|
// Swap previous frame data over.
|
|
PrevVirtualShadowMapId = CurrentVirtualShadowMapId;
|
|
PrevPageSpaceLocation = CurrentPageSpaceLocation;
|
|
PrevShadowMapGlobalDepth = CurrentShadowMapGlobalDepth;
|
|
|
|
if (WorldToLight != ClipmapCacheValidKey.WorldToLight)
|
|
{
|
|
PrevVirtualShadowMapId = INDEX_NONE;
|
|
ClipmapCacheValidKey.WorldToLight = WorldToLight;
|
|
}
|
|
|
|
CurrentVirtualShadowMapId = VirtualShadowMapId;
|
|
CurrentPageSpaceLocation = PageSpaceLocation;
|
|
CurrentShadowMapGlobalDepth = GlobalDepth;
|
|
}
|
|
|
|
void FVirtualShadowMapCacheEntry::Update(int32 VirtualShadowMapId, const FWholeSceneProjectedShadowInitializer &InCacheValidKey)
|
|
{
|
|
// Swap previous frame data over.
|
|
PrevPageSpaceLocation = CurrentPageSpaceLocation;
|
|
PrevVirtualShadowMapId = CurrentVirtualShadowMapId;
|
|
PrevShadowMapGlobalDepth = CurrentShadowMapGlobalDepth;
|
|
|
|
// Check cache validity based of shadow setup
|
|
if (!CacheValidKey.IsCachedShadowValid(InCacheValidKey))
|
|
{
|
|
PrevVirtualShadowMapId = INDEX_NONE;
|
|
//UE_LOG(LogRenderer, Display, TEXT("Invalidated!"));
|
|
}
|
|
|
|
CacheValidKey = InCacheValidKey;
|
|
|
|
CurrentVirtualShadowMapId = VirtualShadowMapId;
|
|
PrevPageSpaceLocation = CurrentPageSpaceLocation = FIntPoint(0, 0);
|
|
PrevShadowMapGlobalDepth = CurrentShadowMapGlobalDepth = 0.0f;
|
|
}
|
|
|
|
|
|
TSharedPtr<FVirtualShadowMapCacheEntry> FVirtualShadowMapArrayCacheManager::FindCreateCacheEntry(int32 LightSceneId, int32 CascadeIndex)
|
|
{
|
|
if (CVarCacheVirtualSMs.GetValueOnRenderThread() == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
const FIntPoint Key(LightSceneId, CascadeIndex);
|
|
|
|
if (TSharedPtr<FVirtualShadowMapCacheEntry> *VirtualShadowMapCacheEntry = CacheEntries.Find(Key))
|
|
{
|
|
return *VirtualShadowMapCacheEntry;
|
|
}
|
|
|
|
// Add to current frame / active set.
|
|
TSharedPtr<FVirtualShadowMapCacheEntry> &NewVirtualShadowMapCacheEntry = CacheEntries.Add(Key);
|
|
|
|
// Copy data if available
|
|
if (TSharedPtr<FVirtualShadowMapCacheEntry> *PrevVirtualShadowMapCacheEntry = PrevCacheEntries.Find(Key))
|
|
{
|
|
NewVirtualShadowMapCacheEntry = *PrevVirtualShadowMapCacheEntry;
|
|
}
|
|
else
|
|
{
|
|
NewVirtualShadowMapCacheEntry = TSharedPtr<FVirtualShadowMapCacheEntry>(new FVirtualShadowMapCacheEntry);
|
|
}
|
|
|
|
// return entry
|
|
return NewVirtualShadowMapCacheEntry;
|
|
}
|
|
|
|
|
|
class FVirtualSmCopyStatsCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FVirtualSmCopyStatsCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVirtualSmCopyStatsCS, FGlobalShader)
|
|
public:
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint >, InStatsBuffer)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer< uint >, AccumulatedStatsBufferOut)
|
|
SHADER_PARAMETER(uint32, NumStats)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
|
|
OutEnvironment.SetDefine(TEXT("MAX_STAT_FRAMES"), FVirtualShadowMapArrayCacheManager::MaxStatFrames);
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FVirtualSmCopyStatsCS, "/Engine/Private/VirtualShadowMaps/CopyStats.usf", "CopyStatsCS", SF_Compute);
|
|
|
|
void FVirtualShadowMapArrayCacheManager::ExtractFrameData(FVirtualShadowMapArray &VirtualShadowMapArray, FRDGBuilder& GraphBuilder)
|
|
{
|
|
if (VirtualShadowMapArray.IsAllocated()
|
|
&& CVarCacheVirtualSMs.GetValueOnRenderThread() != 0)
|
|
{
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.PageTableRDG, &PrevPageTable);
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.PageFlagsRDG, &PrevPageFlags);
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.HPageFlagsRDG, &PrevHPageFlags);
|
|
|
|
GraphBuilder.QueueTextureExtraction(VirtualShadowMapArray.PhysicalPagePoolRDG, &PrevPhysicalPagePool);
|
|
|
|
if( VirtualShadowMapArray.PhysicalPagePoolHw )
|
|
{
|
|
GraphBuilder.QueueTextureExtraction(VirtualShadowMapArray.PhysicalPagePoolHw, &PrevPhysicalPagePoolHw);
|
|
}
|
|
else
|
|
{
|
|
PrevPhysicalPagePoolHw = TRefCountPtr<IPooledRenderTarget>();
|
|
}
|
|
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.PhysicalPageMetaDataRDG, &PrevPhysicalPageMetaData);
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.DynamicCasterPageFlagsRDG, &PrevDynamicCasterPageFlags);
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.ShadowMapProjectionDataRDG, &PrevShadowMapProjectionDataBuffer);
|
|
GraphBuilder.QueueBufferExtraction(VirtualShadowMapArray.PageRectBoundsRDG, &PrevPageRectBounds);
|
|
// Move cache entries to previous frame, this implicitly removes any that were not used
|
|
PrevCacheEntries = CacheEntries;
|
|
PrevUniformParameters = VirtualShadowMapArray.UniformParameters;
|
|
}
|
|
else
|
|
{
|
|
// Drop all refs.
|
|
PrevPageTable = TRefCountPtr<FRDGPooledBuffer>();
|
|
PrevPageFlags = TRefCountPtr<FRDGPooledBuffer>();
|
|
PrevHPageFlags = TRefCountPtr<FRDGPooledBuffer>();
|
|
|
|
PrevPhysicalPagePool = TRefCountPtr<IPooledRenderTarget>();
|
|
PrevPhysicalPagePoolHw = TRefCountPtr<IPooledRenderTarget>();
|
|
PrevPhysicalPageMetaData = TRefCountPtr<FRDGPooledBuffer>();
|
|
PrevDynamicCasterPageFlags = TRefCountPtr<FRDGPooledBuffer>();
|
|
PrevShadowMapProjectionDataBuffer = TRefCountPtr<FRDGPooledBuffer>();
|
|
PrevPageRectBounds = TRefCountPtr<FRDGPooledBuffer>();
|
|
|
|
PrevUniformParameters.NumShadowMaps = 0;
|
|
|
|
PrevCacheEntries.Empty();
|
|
}
|
|
CacheEntries.Reset();
|
|
|
|
// Drop any references embedded in the uniform parameters this frame.
|
|
// We'll reestablish them when we reimport the extracted resources next frame
|
|
PrevUniformParameters.ProjectionData = nullptr;
|
|
PrevUniformParameters.PageTable = nullptr;
|
|
PrevUniformParameters.PhysicalPagePool = nullptr;
|
|
PrevUniformParameters.PhysicalPagePoolHw = nullptr;
|
|
|
|
FRDGBufferRef AccumulatedStatsBufferRDG = nullptr;
|
|
|
|
// Note: stats accumulation thing is here because it needs to persist over frames.
|
|
if (!AccumulatedStatsBuffer.IsValid())
|
|
{
|
|
AccumulatedStatsBufferRDG = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(4, 1 + FVirtualShadowMapArray::NumStats * MaxStatFrames), TEXT("Shadow.Virtual.AccumulatedStatsBuffer")); // TODO: Can't be a structured buffer as EnqueueCopy is only defined for vertex buffers
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(AccumulatedStatsBufferRDG, PF_R32_UINT), 0);
|
|
ConvertToExternalBuffer(GraphBuilder, AccumulatedStatsBufferRDG, AccumulatedStatsBuffer);
|
|
}
|
|
else
|
|
{
|
|
AccumulatedStatsBufferRDG = GraphBuilder.RegisterExternalBuffer(AccumulatedStatsBuffer, TEXT("Shadow.Virtual.AccumulatedStatsBuffer"));
|
|
}
|
|
|
|
if (IsAccumulatingStats())
|
|
{
|
|
// Initialize/clear
|
|
if (!bAccumulatingStats)
|
|
{
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(AccumulatedStatsBufferRDG, PF_R32_UINT), 0);
|
|
bAccumulatingStats = true;
|
|
}
|
|
|
|
FVirtualSmCopyStatsCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVirtualSmCopyStatsCS::FParameters>();
|
|
|
|
PassParameters->InStatsBuffer = GraphBuilder.CreateSRV(VirtualShadowMapArray.StatsBufferRDG, PF_R32_UINT);
|
|
PassParameters->AccumulatedStatsBufferOut = GraphBuilder.CreateUAV(AccumulatedStatsBufferRDG, PF_R32_UINT);
|
|
PassParameters->NumStats = FVirtualShadowMapArray::NumStats;
|
|
|
|
auto ComputeShader = GetGlobalShaderMap(GMaxRHIFeatureLevel)->GetShader<FVirtualSmCopyStatsCS>();
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("Copy Stats"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(1, 1, 1)
|
|
);
|
|
}
|
|
else if (bAccumulatingStats)
|
|
{
|
|
bAccumulatingStats = false;
|
|
|
|
GPUBufferReadback = new FRHIGPUBufferReadback(TEXT("Shadow.Virtual.AccumulatedStatsBuffer"));
|
|
AddEnqueueCopyPass(GraphBuilder, GPUBufferReadback, AccumulatedStatsBufferRDG, 0u);
|
|
}
|
|
|
|
if (GPUBufferReadback && GPUBufferReadback->IsReady())
|
|
{
|
|
TArray<uint32> Tmp;
|
|
Tmp.AddDefaulted(1 + FVirtualShadowMapArray::NumStats * MaxStatFrames);
|
|
|
|
{
|
|
const uint32* BufferPtr = (const uint32*)GPUBufferReadback->Lock((1 + FVirtualShadowMapArray::NumStats * MaxStatFrames) * sizeof(uint32));
|
|
FPlatformMemory::Memcpy(Tmp.GetData(), BufferPtr, Tmp.Num() * Tmp.GetTypeSize());
|
|
GPUBufferReadback->Unlock();
|
|
|
|
delete GPUBufferReadback;
|
|
GPUBufferReadback = nullptr;
|
|
}
|
|
|
|
FString FileName = TEXT("VirtualShadowMapCacheStats.csv");// FString::Printf(TEXT("%s.csv"), *FileNameToUse);
|
|
FArchive * FileToLogTo = IFileManager::Get().CreateFileWriter(*FileName, false);
|
|
ensure(FileToLogTo);
|
|
if (FileToLogTo)
|
|
{
|
|
static const FString StatNames[FVirtualShadowMapArray::NumStats] =
|
|
{
|
|
TEXT("Allocated"),
|
|
TEXT("Cached"),
|
|
TEXT("Dynamic"),
|
|
TEXT("NumSms"),
|
|
TEXT("RandRobin"),
|
|
};
|
|
|
|
|
|
// Print header
|
|
FString StringToPrint;
|
|
for (const FString &StatName : StatNames)
|
|
{
|
|
if (!StringToPrint.IsEmpty())
|
|
{
|
|
StringToPrint += TEXT(",");
|
|
}
|
|
|
|
StringToPrint += StatName;
|
|
}
|
|
|
|
StringToPrint += TEXT("\n");
|
|
FileToLogTo->Serialize(TCHAR_TO_ANSI(*StringToPrint), StringToPrint.Len());
|
|
|
|
uint32 Num = Tmp[0];
|
|
for (uint32 Ind = 0; Ind < Num; ++Ind)
|
|
{
|
|
StringToPrint.Empty();
|
|
|
|
for (uint32 StatInd = 0; StatInd < FVirtualShadowMapArray::NumStats; ++StatInd)
|
|
{
|
|
if (!StringToPrint.IsEmpty())
|
|
{
|
|
StringToPrint += TEXT(",");
|
|
}
|
|
|
|
StringToPrint += FString::Printf(TEXT("%d"), Tmp[1 + Ind * FVirtualShadowMapArray::NumStats + StatInd]);
|
|
}
|
|
|
|
StringToPrint += TEXT("\n");
|
|
FileToLogTo->Serialize(TCHAR_TO_ANSI(*StringToPrint), StringToPrint.Len());
|
|
}
|
|
|
|
|
|
FileToLogTo->Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FVirtualShadowMapArrayCacheManager::IsValid()
|
|
{
|
|
return CVarCacheVirtualSMs.GetValueOnRenderThread() != 0
|
|
&& PrevPageTable
|
|
&& PrevPageFlags
|
|
&& (PrevPhysicalPagePool || PrevPhysicalPagePoolHw)
|
|
&& PrevPhysicalPageMetaData
|
|
&& PrevDynamicCasterPageFlags;
|
|
}
|
|
|
|
|
|
bool FVirtualShadowMapArrayCacheManager::IsAccumulatingStats()
|
|
{
|
|
return CVarAccumulateStats.GetValueOnRenderThread() != 0;
|
|
}
|
|
|
|
void FVirtualShadowMapArrayCacheManager::ProcessRemovedPrimives(FRDGBuilder& GraphBuilder, const FGPUScene &GPUScene, const TArray<FPrimitiveSceneInfo*> &RemovedPrimitiveSceneInfos)
|
|
{
|
|
if (CVarCacheVirtualSMs.GetValueOnRenderThread() != 0 && RemovedPrimitiveSceneInfos.Num() > 0 && PrevDynamicCasterPageFlags.IsValid())
|
|
{
|
|
// Note: Could filter out primitives that have no nanite here (though later this might be bad anyway, when regular geo is also rendered into virtual SMs)
|
|
TArray<FInstanceDataRange> InstanceRangesLarge;
|
|
TArray<FInstanceDataRange> InstanceRangesSmall;
|
|
for (const FPrimitiveSceneInfo* PrimitiveSceneInfo : RemovedPrimitiveSceneInfos)
|
|
{
|
|
if (PrimitiveSceneInfo->GetInstanceDataOffset() != INDEX_NONE)
|
|
{
|
|
int32 NumInstanceDataEntries = PrimitiveSceneInfo->GetNumInstanceDataEntries();
|
|
if (NumInstanceDataEntries >= 8U)
|
|
{
|
|
InstanceRangesLarge.Add(FInstanceDataRange{ PrimitiveSceneInfo->GetInstanceDataOffset(), NumInstanceDataEntries });
|
|
}
|
|
else
|
|
{
|
|
InstanceRangesSmall.Add(FInstanceDataRange{ PrimitiveSceneInfo->GetInstanceDataOffset(), NumInstanceDataEntries });
|
|
}
|
|
}
|
|
}
|
|
ProcessInstanceRangeInvalidation(GraphBuilder, InstanceRangesLarge, InstanceRangesSmall, GPUScene);
|
|
}
|
|
}
|
|
|
|
|
|
void FVirtualShadowMapArrayCacheManager::ProcessPrimitivesToUpdate(FRDGBuilder& GraphBuilder, const FScene &Scene)
|
|
{
|
|
const FGPUScene& GPUScene = Scene.GPUScene;
|
|
if (IsValid() && GPUScene.PrimitivesToUpdate.Num() > 0)
|
|
{
|
|
// TODO: As a slight CPU optimization just pass primitive ID list and use instance ranges stored in GPU scene
|
|
TArray<FInstanceDataRange> InstanceRangesLarge;
|
|
TArray<FInstanceDataRange> InstanceRangesSmall;
|
|
for (const int32 PrimitiveId : GPUScene.PrimitivesToUpdate)
|
|
{
|
|
// Skip added ones (they dont need it, but must be marked as having moved).
|
|
if (PrimitiveId < Scene.Primitives.Num() && (PrimitiveId >= GPUScene.AddedPrimitiveFlags.Num() || !GPUScene.AddedPrimitiveFlags[PrimitiveId]))
|
|
{
|
|
const FPrimitiveSceneInfo* PrimitiveSceneInfo = Scene.Primitives[PrimitiveId];
|
|
if (PrimitiveSceneInfo->GetInstanceDataOffset() != INDEX_NONE)
|
|
{
|
|
int32 NumInstanceDataEntries = PrimitiveSceneInfo->GetNumInstanceDataEntries();
|
|
if (NumInstanceDataEntries >= 8U)
|
|
{
|
|
InstanceRangesLarge.Add(FInstanceDataRange{ PrimitiveSceneInfo->GetInstanceDataOffset(), NumInstanceDataEntries });
|
|
}
|
|
else
|
|
{
|
|
InstanceRangesSmall.Add(FInstanceDataRange{ PrimitiveSceneInfo->GetInstanceDataOffset(), NumInstanceDataEntries });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ProcessInstanceRangeInvalidation(GraphBuilder, InstanceRangesLarge, InstanceRangesSmall, GPUScene);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Compute shader to project and invalidate the rectangles of given instances.
|
|
*/
|
|
class FVirtualSmInvalidateInstancePagesCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FVirtualSmInvalidateInstancePagesCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVirtualSmInvalidateInstancePagesCS, FGlobalShader)
|
|
|
|
class FLargeSmallDim : SHADER_PERMUTATION_BOOL("PROCESS_LARGE_INSTANCE_COUNT_RANGES");
|
|
using FPermutationDomain = TShaderPermutationDomain<FLargeSmallDim>;
|
|
|
|
public:
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FVirtualShadowMapUniformParameters, VirtualShadowMap)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< FInstanceDataRange >, InstanceRanges)
|
|
SHADER_PARAMETER(uint32, NumRemovedItems)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint >, PageFlags)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint >, HPageFlags)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint4 >, PageRectBounds)
|
|
SHADER_PARAMETER_RDG_BUFFER_UAV(RWStructuredBuffer< uint >, OutDynamicCasterFlags)
|
|
|
|
SHADER_PARAMETER_SRV(StructuredBuffer<float4>, GPUSceneInstanceSceneData)
|
|
SHADER_PARAMETER_SRV(StructuredBuffer<float4>, GPUScenePrimitiveSceneData)
|
|
SHADER_PARAMETER(uint32, GPUSceneFrameNumber)
|
|
SHADER_PARAMETER(uint32, InstanceDataSOAStride)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static constexpr int Cs1dGroupSizeX = 64;
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
FVirtualShadowMapArray::SetShaderDefines(OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("CS_1D_GROUP_SIZE_X"), Cs1dGroupSizeX);
|
|
OutEnvironment.SetDefine(TEXT("USE_GLOBAL_GPU_SCENE_DATA"), 1);
|
|
OutEnvironment.SetDefine(TEXT("VF_SUPPORTS_PRIMITIVE_SCENE_DATA"), 1);
|
|
|
|
// OutEnvironment.SetDefine(TEXT("MAX_STAT_FRAMES"), FVirtualShadowMapArrayCacheManager::MaxStatFrames);
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FVirtualSmInvalidateInstancePagesCS, "/Engine/Private/VirtualShadowMaps/CacheManagement.usf", "VirtualSmInvalidateInstancePagesCS", SF_Compute);
|
|
|
|
|
|
TRDGUniformBufferRef<FVirtualShadowMapUniformParameters> FVirtualShadowMapArrayCacheManager::GetPreviousUniformBuffer(FRDGBuilder& GraphBuilder) const
|
|
{
|
|
FVirtualShadowMapUniformParameters* VersionedParameters = GraphBuilder.AllocParameters<FVirtualShadowMapUniformParameters>();
|
|
*VersionedParameters = PrevUniformParameters;
|
|
return GraphBuilder.CreateUniformBuffer(VersionedParameters);
|
|
}
|
|
|
|
void FVirtualShadowMapArrayCacheManager::ProcessInstanceRangeInvalidation(FRDGBuilder& GraphBuilder, const TArray<FInstanceDataRange>& InstanceRangesLarge, const TArray<FInstanceDataRange>& InstanceRangesSmall, const FGPUScene& GPUScene)
|
|
{
|
|
auto RegExtCreateSrv = [&GraphBuilder](const TRefCountPtr<FRDGPooledBuffer>& Buffer, const TCHAR* Name) -> FRDGBufferSRVRef
|
|
{
|
|
return GraphBuilder.CreateSRV(GraphBuilder.RegisterExternalBuffer(Buffer, Name));
|
|
};
|
|
|
|
// Update references in our last frame uniform buffer with reimported resources for this frame
|
|
PrevUniformParameters.ProjectionData = RegExtCreateSrv(PrevShadowMapProjectionDataBuffer, TEXT("Shadow.Virtual.PrevProjectionData"));
|
|
PrevUniformParameters.PageTable = RegExtCreateSrv(PrevPageTable, TEXT("Shadow.Virtual.PrevPageTable"));
|
|
// Unused in this path
|
|
PrevUniformParameters.PhysicalPagePool = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
|
|
PrevUniformParameters.PhysicalPagePoolHw = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
|
|
|
|
if (InstanceRangesSmall.Num())
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "ProcessInstanceRangeInvalidation [%d small-ranges]", InstanceRangesSmall.Num());
|
|
|
|
FVirtualSmInvalidateInstancePagesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVirtualSmInvalidateInstancePagesCS::FParameters>();
|
|
|
|
PassParameters->VirtualShadowMap = GetPreviousUniformBuffer(GraphBuilder);
|
|
FRDGBufferRef InstanceRangesRDG = CreateStructuredBuffer(GraphBuilder, TEXT("Shadow.Virtual.InstanceRangesSmall"), InstanceRangesSmall);
|
|
PassParameters->InstanceRanges = GraphBuilder.CreateSRV(InstanceRangesRDG);
|
|
PassParameters->NumRemovedItems = InstanceRangesSmall.Num();
|
|
|
|
PassParameters->PageFlags = RegExtCreateSrv(PrevPageFlags, TEXT("Shadow.Virtual.PrevPageFlags"));
|
|
PassParameters->HPageFlags = RegExtCreateSrv(PrevHPageFlags, TEXT("Shadow.Virtual.PrevHPageFlags"));
|
|
PassParameters->PageRectBounds = RegExtCreateSrv(PrevPageRectBounds, TEXT("Shadow.Virtual.PrevPageRectBounds"));
|
|
|
|
FRDGBufferRef DynamicCasterFlagsRDG = GraphBuilder.RegisterExternalBuffer(PrevDynamicCasterPageFlags, TEXT("Shadow.Virtual.DynamicCasterFlags"));
|
|
PassParameters->OutDynamicCasterFlags = GraphBuilder.CreateUAV(DynamicCasterFlagsRDG);
|
|
|
|
PassParameters->GPUSceneInstanceSceneData = GPUScene.InstanceDataBuffer.SRV;
|
|
PassParameters->GPUScenePrimitiveSceneData = GPUScene.PrimitiveBuffer.SRV;
|
|
PassParameters->GPUSceneFrameNumber = GPUScene.GetSceneFrameNumber();
|
|
PassParameters->InstanceDataSOAStride = GPUScene.InstanceDataSOAStride;
|
|
|
|
FVirtualSmInvalidateInstancePagesCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FVirtualSmInvalidateInstancePagesCS::FLargeSmallDim>(0);
|
|
|
|
auto ComputeShader = GetGlobalShaderMap(GMaxRHIFeatureLevel)->GetShader<FVirtualSmInvalidateInstancePagesCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("VirtualSmInvalidateInstancePagesCS"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(FMath::DivideAndRoundUp(InstanceRangesSmall.Num(), FVirtualSmInvalidateInstancePagesCS::Cs1dGroupSizeX), 1, 1)
|
|
);
|
|
}
|
|
if (InstanceRangesLarge.Num())
|
|
{
|
|
RDG_EVENT_SCOPE(GraphBuilder, "ProcessInstanceRangeInvalidation [%d large-ranges]", InstanceRangesLarge.Num());
|
|
|
|
FVirtualSmInvalidateInstancePagesCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVirtualSmInvalidateInstancePagesCS::FParameters>();
|
|
|
|
PassParameters->VirtualShadowMap = GetPreviousUniformBuffer(GraphBuilder);
|
|
FRDGBufferRef InstanceRangesRDG = CreateStructuredBuffer(GraphBuilder, TEXT("Shadow.Virtual.InstanceRangesSmall"), InstanceRangesLarge);
|
|
PassParameters->InstanceRanges = GraphBuilder.CreateSRV(InstanceRangesRDG);
|
|
PassParameters->NumRemovedItems = InstanceRangesLarge.Num();
|
|
|
|
PassParameters->PageFlags = RegExtCreateSrv(PrevPageFlags, TEXT("Shadow.Virtual.PrevPageFlags"));
|
|
PassParameters->HPageFlags = RegExtCreateSrv(PrevHPageFlags, TEXT("Shadow.Virtual.PrevHPageFlags"));
|
|
PassParameters->PageRectBounds = RegExtCreateSrv(PrevPageRectBounds, TEXT("Shadow.Virtual.PrevPageRectBounds"));
|
|
|
|
FRDGBufferRef DynamicCasterFlagsRDG = GraphBuilder.RegisterExternalBuffer(PrevDynamicCasterPageFlags, TEXT("Shadow.Virtual.DynamicCasterFlags"));
|
|
PassParameters->OutDynamicCasterFlags = GraphBuilder.CreateUAV(DynamicCasterFlagsRDG);
|
|
|
|
PassParameters->GPUSceneInstanceSceneData = GPUScene.InstanceDataBuffer.SRV;
|
|
PassParameters->GPUScenePrimitiveSceneData = GPUScene.PrimitiveBuffer.SRV;
|
|
PassParameters->GPUSceneFrameNumber = GPUScene.GetSceneFrameNumber();
|
|
PassParameters->InstanceDataSOAStride = GPUScene.InstanceDataSOAStride;
|
|
|
|
FVirtualSmInvalidateInstancePagesCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set<FVirtualSmInvalidateInstancePagesCS::FLargeSmallDim>(1);
|
|
|
|
auto ComputeShader = GetGlobalShaderMap(GMaxRHIFeatureLevel)->GetShader<FVirtualSmInvalidateInstancePagesCS>(PermutationVector);
|
|
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
RDG_EVENT_NAME("VirtualSmInvalidateInstancePagesCS"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector(InstanceRangesLarge.Num(), 1, 1)
|
|
);
|
|
}
|
|
}
|