void FProjectedShadowInfo::GatherDynamicMeshElements(FSceneRenderer& Renderer, FVisibleLightInfo& VisibleLightInfo, TArray<const FSceneView*>& ReusedViewsArray,
FGlobalDynamicIndexBuffer& DynamicIndexBuffer, FGlobalDynamicVertexBuffer& DynamicVertexBuffer, FGlobalDynamicReadBuffer& DynamicReadBuffer)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_Shadow_GatherDynamicMeshElements);
check(ShadowDepthView && IsInRenderingThread());
if (DynamicSubjectPrimitives.Num() > 0 || ReceiverPrimitives.Num() > 0 || SubjectTranslucentPrimitives.Num() > 0)
{
// Backup properties of the view that we will override
FMatrix OriginalViewMatrix = ShadowDepthView->ViewMatrices.GetViewMatrix();
// Override the view matrix so that billboarding primitives will be aligned to the light
ShadowDepthView->ViewMatrices.HackOverrideViewMatrixForShadows(ShadowViewMatrix);
ReusedViewsArray[0] = ShadowDepthView;
if (bPreShadow && GPreshadowsForceLowestLOD)
{
ShadowDepthView->DrawDynamicFlags = EDrawDynamicFlags::ForceLowestLOD;
}
if (CascadeSettings.bFarShadowCascade)
{
(int32&)ShadowDepthView->DrawDynamicFlags |= (int32)EDrawDynamicFlags::FarShadowCascade;
}
if (IsWholeSceneDirectionalShadow())
{
ShadowDepthView->SetPreShadowTranslation(FVector(0, 0, 0));
ShadowDepthView->SetDynamicMeshElementsShadowCullFrustum(&CascadeSettings.ShadowBoundsAccurate);
GatherDynamicMeshElementsArray(ShadowDepthView, Renderer, DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer,
DynamicSubjectPrimitives, ReusedViewsArray, DynamicSubjectMeshElements, NumDynamicSubjectMeshElements);
ShadowDepthView->SetPreShadowTranslation(PreShadowTranslation);
}
else
{
ShadowDepthView->SetPreShadowTranslation(PreShadowTranslation);
ShadowDepthView->SetDynamicMeshElementsShadowCullFrustum(&CasterFrustum);
GatherDynamicMeshElementsArray(ShadowDepthView, Renderer, DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer,
DynamicSubjectPrimitives, ReusedViewsArray, DynamicSubjectMeshElements, NumDynamicSubjectMeshElements);
}
ShadowDepthView->DrawDynamicFlags = EDrawDynamicFlags::None;
int32 NumDynamicSubjectTranslucentMeshElements = 0;
ShadowDepthView->SetDynamicMeshElementsShadowCullFrustum(&CasterFrustum);
GatherDynamicMeshElementsArray(ShadowDepthView, Renderer, DynamicIndexBuffer, DynamicVertexBuffer, DynamicReadBuffer,
SubjectTranslucentPrimitives, ReusedViewsArray, DynamicSubjectTranslucentMeshElements, NumDynamicSubjectTranslucentMeshElements);
Renderer.MeshCollector.ProcessTasks();
}
// Create a pass uniform buffer so we can build mesh commands now in InitDynamicShadows. This will be updated with the correct contents just before the actual pass.
const EShadingPath ShadingPath = FSceneInterface::GetShadingPath(Renderer.FeatureLevel);
FRHIUniformBuffer* PassUniformBuffer = nullptr;
if (ShadingPath == EShadingPath::Deferred)
{
FShadowDepthPassUniformParameters ShadowDepthParameters;
ShadowDepthPassUniformBuffer = TUniformBufferRef<FShadowDepthPassUniformParameters>::CreateUniformBufferImmediate(ShadowDepthParameters, UniformBuffer_MultiFrame, EUniformBufferValidation::None);
PassUniformBuffer = ShadowDepthPassUniformBuffer;
}
else if (ShadingPath == EShadingPath::Mobile)
{
FMobileShadowDepthPassUniformParameters ShadowDepthParameters;
MobileShadowDepthPassUniformBuffer = TUniformBufferRef<FMobileShadowDepthPassUniformParameters>::CreateUniformBufferImmediate(ShadowDepthParameters, UniformBuffer_MultiFrame, EUniformBufferValidation::None);
PassUniformBuffer = MobileShadowDepthPassUniformBuffer;
}
SetupMeshDrawCommandsForShadowDepth(Renderer, PassUniformBuffer);
SetupMeshDrawCommandsForProjectionStenciling(Renderer);
}
ShadowSetup.cpp?
void FProjectedShadowInfo::SetupMeshDrawCommandsForShadowDepth(FSceneRenderer& Renderer, FRHIUniformBuffer* PassUniformBuffer)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_SetupMeshDrawCommandsForShadowDepth);
FShadowDepthPassMeshProcessor* MeshPassProcessor = new(FMemStack::Get()) FShadowDepthPassMeshProcessor(
Renderer.Scene,
ShadowDepthView,
ShadowDepthView->ViewUniformBuffer,
PassUniformBuffer,
GetShadowDepthType(),
nullptr);
if (Renderer.ShouldDumpMeshDrawCommandInstancingStats())
{
FString PassNameForStats;
GetShadowTypeNameForDrawEvent(PassNameForStats);
ShadowDepthPass.SetDumpInstancingStats(TEXT("ShadowDepth ") + PassNameForStats);
}
const uint32 InstanceFactor = !GetShadowDepthType().bOnePassPointLightShadow || RHISupportsGeometryShaders(Renderer.Scene->GetShaderPlatform()) ? 1 : 6;
ShadowDepthPass.DispatchPassSetup(
Renderer.Scene,
*ShadowDepthView,
EMeshPass::Num,
FExclusiveDepthStencil::DepthNop_StencilNop,
MeshPassProcessor,
DynamicSubjectMeshElements,
nullptr,
NumDynamicSubjectMeshElements * InstanceFactor,
SubjectMeshCommandBuildRequests,
NumSubjectMeshCommandBuildRequestElements * InstanceFactor,
ShadowDepthPassVisibleCommands);
Renderer.DispatchedShadowDepthPasses.Add(&ShadowDepthPass);
}
void FParallelMeshDrawCommandPass::DispatchPassSetup(
FScene* Scene,
const FViewInfo& View,
EMeshPass::Type PassType,
FExclusiveDepthStencil::Type BasePassDepthStencilAccess,
FMeshPassProcessor* MeshPassProcessor,
const TArray<FMeshBatchAndRelevance, SceneRenderingAllocator>& DynamicMeshElements,
const TArray<FMeshPassMask, SceneRenderingAllocator>* DynamicMeshElementsPassRelevance,
int32 NumDynamicMeshElements,
TArray<const FStaticMeshBatch*, SceneRenderingAllocator>& InOutDynamicMeshCommandBuildRequests,
int32 NumDynamicMeshCommandBuildRequestElements,
FMeshCommandOneFrameArray& InOutMeshDrawCommands,
FMeshPassProcessor* MobileBasePassCSMMeshPassProcessor,
FMeshCommandOneFrameArray* InOutMobileBasePassCSMMeshDrawCommands
)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ParallelMdcDispatchPassSetup);
check(!TaskEventRef.IsValid() && MeshPassProcessor != nullptr && TaskContext.PrimitiveIdBufferData == nullptr);
check((PassType == EMeshPass::Num) == (DynamicMeshElementsPassRelevance == nullptr));
MaxNumDraws = InOutMeshDrawCommands.Num() + NumDynamicMeshElements + NumDynamicMeshCommandBuildRequestElements;
TaskContext.MeshPassProcessor = MeshPassProcessor;
TaskContext.MobileBasePassCSMMeshPassProcessor = MobileBasePassCSMMeshPassProcessor;
TaskContext.DynamicMeshElements = &DynamicMeshElements;
TaskContext.DynamicMeshElementsPassRelevance = DynamicMeshElementsPassRelevance;
TaskContext.View = &View;
TaskContext.ShadingPath = Scene->GetShadingPath();
TaskContext.ShaderPlatform = Scene->GetShaderPlatform();
TaskContext.PassType = PassType;
TaskContext.bUseGPUScene = UseGPUScene(GMaxRHIShaderPlatform, View.GetFeatureLevel());
TaskContext.bDynamicInstancing = IsDynamicInstancingEnabled(View.GetFeatureLevel());
TaskContext.bReverseCulling = View.bReverseCulling;
TaskContext.bRenderSceneTwoSided = View.bRenderSceneTwoSided;
TaskContext.BasePassDepthStencilAccess = BasePassDepthStencilAccess;
TaskContext.DefaultBasePassDepthStencilAccess = Scene->DefaultBasePassDepthStencilAccess;
TaskContext.NumDynamicMeshElements = NumDynamicMeshElements;
TaskContext.NumDynamicMeshCommandBuildRequestElements = NumDynamicMeshCommandBuildRequestElements;
// Only apply instancing for ISR to main view passes
const bool bIsMainViewPass = PassType != EMeshPass::Num && (FPassProcessorManager::GetPassFlags(TaskContext.ShadingPath, TaskContext.PassType) & EMeshPassFlags::MainView) != EMeshPassFlags::None;
TaskContext.InstanceFactor = (bIsMainViewPass && View.IsInstancedStereoPass()) ? 2 : 1;
// Setup translucency sort key update pass based on view.
TaskContext.TranslucencyPass = ETranslucencyPass::TPT_MAX;
TaskContext.TranslucentSortPolicy = View.TranslucentSortPolicy;
TaskContext.TranslucentSortAxis = View.TranslucentSortAxis;
TaskContext.ViewOrigin = View.ViewMatrices.GetViewOrigin();
TaskContext.ViewMatrix = View.ViewMatrices.GetViewMatrix();
TaskContext.PrimitiveBounds = &Scene->PrimitiveBounds;
switch (PassType)
{
case EMeshPass::TranslucencyStandard: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_StandardTranslucency; break;
case EMeshPass::TranslucencyAfterDOF: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterDOF; break;
case EMeshPass::TranslucencyAfterDOFModulate: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_TranslucencyAfterDOFModulate; break;
case EMeshPass::TranslucencyAll: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_AllTranslucency; break;
case EMeshPass::MobileInverseOpacity: TaskContext.TranslucencyPass = ETranslucencyPass::TPT_StandardTranslucency; break;
}
FMemory::Memswap(&TaskContext.MeshDrawCommands, &InOutMeshDrawCommands, sizeof(InOutMeshDrawCommands));
FMemory::Memswap(&TaskContext.DynamicMeshCommandBuildRequests, &InOutDynamicMeshCommandBuildRequests, sizeof(InOutDynamicMeshCommandBuildRequests));
if (TaskContext.ShadingPath == EShadingPath::Mobile && TaskContext.PassType == EMeshPass::BasePass)
{
FMemory::Memswap(&TaskContext.MobileBasePassCSMMeshDrawCommands, InOutMobileBasePassCSMMeshDrawCommands, sizeof(*InOutMobileBasePassCSMMeshDrawCommands));
}
else
{
check(MobileBasePassCSMMeshPassProcessor == nullptr && InOutMobileBasePassCSMMeshDrawCommands == nullptr);
}
if (MaxNumDraws > 0)
{
// Preallocate resources on rendering thread based on MaxNumDraws.
bPrimitiveIdBufferDataOwnedByRHIThread = false;
TaskContext.PrimitiveIdBufferDataSize = TaskContext.InstanceFactor * MaxNumDraws * sizeof(int32);
TaskContext.PrimitiveIdBufferData = FMemory::Malloc(TaskContext.PrimitiveIdBufferDataSize);
PrimitiveIdVertexBufferPoolEntry = GPrimitiveIdVertexBufferPool.Allocate(TaskContext.PrimitiveIdBufferDataSize);
TaskContext.MeshDrawCommands.Reserve(MaxNumDraws);
TaskContext.TempVisibleMeshDrawCommands.Reserve(MaxNumDraws);
const bool bExecuteInParallel = FApp::ShouldUseThreadingForPerformance()
&& CVarMeshDrawCommandsParallelPassSetup.GetValueOnRenderThread() > 0
&& GIsThreadedRendering; // Rendering thread is required to safely use rendering resources in parallel.
if (bExecuteInParallel)
{
if (GAllowOnDemandShaderCreation && RHISupportsMultithreadedShaderCreation(GMaxRHIShaderPlatform))
{
TaskEventRef = TGraphTask<FMeshDrawCommandPassSetupTask>::CreateTask(nullptr, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext);
}
else
{
FGraphEventArray DependentGraphEvents;
DependentGraphEvents.Add(TGraphTask<FMeshDrawCommandPassSetupTask>::CreateTask(nullptr, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext));
TaskEventRef = TGraphTask<FMeshDrawCommandInitResourcesTask>::CreateTask(&DependentGraphEvents, ENamedThreads::GetRenderThread()).ConstructAndDispatchWhenReady(TaskContext);
}
}
else
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_MeshPassSetupImmediate);
FMeshDrawCommandPassSetupTask Task(TaskContext);
Task.AnyThreadTask();
if (!GAllowOnDemandShaderCreation || !RHISupportsMultithreadedShaderCreation(GMaxRHIShaderPlatform))
{
FMeshDrawCommandInitResourcesTask DependentTask(TaskContext);
DependentTask.AnyThreadTask();
}
}
}
}
|