UE4阴影渲染【2】

处理ShadowMapAtlases

FSceneRenderer::RenderShadowDepthMapAtlases(RHICmdList);

void FSceneRenderer::RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICmdList)
{
	check(RHICmdList.IsOutsideRenderPass());

	// Perform setup work on all GPUs in case any cached shadows are being updated this
	// frame. We revert to the AllViewsGPUMask for uncached shadows.
	SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());

	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);

	bool bCanUseParallelDispatch = RHICmdList.IsImmediate() &&  // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
		GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread();

	for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.ShadowMapAtlases.Num(); AtlasIndex++)
	{
		const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.ShadowMapAtlases[AtlasIndex];
		FSceneRenderTargetItem& RenderTarget = ShadowMapAtlas.RenderTargets.DepthTarget->GetRenderTargetItem();
		FIntPoint AtlasSize = ShadowMapAtlas.RenderTargets.DepthTarget->GetDesc().Extent;

		GVisualizeTexture.SetCheckPoint(RHICmdList, ShadowMapAtlas.RenderTargets.DepthTarget.GetReference());

		SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("Atlas%u %ux%u"), AtlasIndex, AtlasSize.X, AtlasSize.Y);

		auto BeginShadowRenderPass = [this, &RenderTarget, &SceneContext](FRHICommandList& InRHICmdList, bool bPerformClear)
		{
			check(RenderTarget.TargetableTexture->GetDepthClearValue() == 1.0f);

			ERenderTargetLoadAction DepthLoadAction = bPerformClear ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad;

			FRHIRenderPassInfo RPInfo(RenderTarget.TargetableTexture, MakeDepthStencilTargetActions(MakeRenderTargetActions(DepthLoadAction, ERenderTargetStoreAction::EStore), ERenderTargetActions::DontLoad_DontStore), nullptr, FExclusiveDepthStencil::DepthWrite_StencilNop);

			if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
			{
				RPInfo.ColorRenderTargets[0].Action = ERenderTargetActions::DontLoad_DontStore;
				RPInfo.ColorRenderTargets[0].RenderTarget = SceneContext.GetOptionalShadowDepthColorSurface(InRHICmdList, RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetTexture2D()->GetSizeX(), RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetTexture2D()->GetSizeY());
				InRHICmdList.Transition(FRHITransitionInfo(RPInfo.ColorRenderTargets[0].RenderTarget, ERHIAccess::Unknown, ERHIAccess::RTV));
			}
			InRHICmdList.Transition(FRHITransitionInfo(RPInfo.DepthStencilRenderTarget.DepthStencilTarget, ERHIAccess::Unknown, ERHIAccess::DSVWrite));
			InRHICmdList.BeginRenderPass(RPInfo, TEXT("ShadowMapAtlases"));
		};

		TArray<FProjectedShadowInfo*, SceneRenderingAllocator> ParallelShadowPasses;
		TArray<FProjectedShadowInfo*, SceneRenderingAllocator> SerialShadowPasses;

		// Gather our passes here to minimize switching renderpasses
		for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
		{
			FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];

			const bool bDoParallelDispatch = bCanUseParallelDispatch &&
				(ProjectedShadowInfo->IsWholeSceneDirectionalShadow() || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread());

			if (bDoParallelDispatch)
			{
				ParallelShadowPasses.Add(ProjectedShadowInfo);
			}
			else
			{
				SerialShadowPasses.Add(ProjectedShadowInfo);
			}
		}

		FLightSceneProxy* CurrentLightForDrawEvent = NULL;

#if WANTS_DRAW_MESH_EVENTS
		FDrawEvent LightEvent;
#endif

		if (ParallelShadowPasses.Num() > 0)
		{
			{
				// Clear before going wide.
				SCOPED_DRAW_EVENT(RHICmdList, SetShadowRTsAndClear);
				BeginShadowRenderPass(RHICmdList, true);
				RHICmdList.EndRenderPass();
			}

			for (int32 ShadowIndex = 0; ShadowIndex < ParallelShadowPasses.Num(); ShadowIndex++)
			{
				FProjectedShadowInfo* ProjectedShadowInfo = ParallelShadowPasses[ShadowIndex];
				SCOPED_GPU_MASK(RHICmdList, GetGPUMaskForShadow(ProjectedShadowInfo));

				if (!CurrentLightForDrawEvent || ProjectedShadowInfo->GetLightSceneInfo().Proxy != CurrentLightForDrawEvent)
				{
					if (CurrentLightForDrawEvent)
					{
						SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
						STOP_DRAW_EVENT(LightEvent);
					}

					CurrentLightForDrawEvent = ProjectedShadowInfo->GetLightSceneInfo().Proxy;
					FString LightNameWithLevel;
					GetLightNameForDrawEvent(CurrentLightForDrawEvent, LightNameWithLevel);

					SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
					BEGIN_DRAW_EVENTF(
						RHICmdList,
						LightNameEvent,
						LightEvent,
						*LightNameWithLevel);
				}
				ProjectedShadowInfo->SetupShadowUniformBuffers(RHICmdList, Scene);
				ProjectedShadowInfo->TransitionCachedShadowmap(RHICmdList, Scene);
				ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, true);
			}
		}

		if (CurrentLightForDrawEvent)
		{
			SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
			STOP_DRAW_EVENT(LightEvent);
		}

		CurrentLightForDrawEvent = nullptr;

		if (SerialShadowPasses.Num() > 0)
		{
			bool bShadowDepthCleared = ParallelShadowPasses.Num() > 0;
			bool bForceSingleRenderPass = CVarShadowForceSerialSingleRenderPass.GetValueOnAnyThread() != 0;
			if (bForceSingleRenderPass)
			{
				SCOPED_GPU_MASK(RHICmdList, AllViewsGPUMask);
				BeginShadowRenderPass(RHICmdList, !bShadowDepthCleared);
			}


			for (int32 ShadowIndex = 0; ShadowIndex < SerialShadowPasses.Num(); ShadowIndex++)
			{
				FProjectedShadowInfo* ProjectedShadowInfo = SerialShadowPasses[ShadowIndex];
				SCOPED_GPU_MASK(RHICmdList, GetGPUMaskForShadow(ProjectedShadowInfo));

				if (!CurrentLightForDrawEvent || ProjectedShadowInfo->GetLightSceneInfo().Proxy != CurrentLightForDrawEvent)
				{
					if (CurrentLightForDrawEvent)
					{
						SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
						STOP_DRAW_EVENT(LightEvent);
					}

					CurrentLightForDrawEvent = ProjectedShadowInfo->GetLightSceneInfo().Proxy;
					FString LightNameWithLevel;
					GetLightNameForDrawEvent(CurrentLightForDrawEvent, LightNameWithLevel);

					SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
					BEGIN_DRAW_EVENTF(
						RHICmdList,
						LightNameEvent,
						LightEvent,
						*LightNameWithLevel);
				}

				ProjectedShadowInfo->SetupShadowUniformBuffers(RHICmdList, Scene);
				ProjectedShadowInfo->TransitionCachedShadowmap(RHICmdList, Scene);
#if WITH_MGPU
				// In case the first shadow is view-dependent, ensure we do the clear on all GPUs.
				FRHIGPUMask GPUMaskForRenderPass = RHICmdList.GetGPUMask();
				if (ShadowIndex == 0)
				{
					// This ensures that we don't downgrade the GPU mask if the first shadow is a
					// cached whole scene shadow.
					GPUMaskForRenderPass |= AllViewsGPUMask;
				}
#endif
				if (!bForceSingleRenderPass)
				{
					SCOPED_GPU_MASK(RHICmdList, GPUMaskForRenderPass);
					BeginShadowRenderPass(RHICmdList, ShadowIndex == 0 && !bShadowDepthCleared);
				}
				ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, false);
				if (!bForceSingleRenderPass)
				{
					RHICmdList.EndRenderPass();
				}
			}
			if (bForceSingleRenderPass)
			{
				SCOPED_GPU_MASK(RHICmdList, AllViewsGPUMask);
				RHICmdList.EndRenderPass();
			}
		}

		if (CurrentLightForDrawEvent)
		{
			SCOPED_GPU_MASK(RHICmdList, FRHIGPUMask::All());
			STOP_DRAW_EVENT(LightEvent);
			CurrentLightForDrawEvent = NULL;
		}

		RHICmdList.Transition(FRHITransitionInfo(RenderTarget.TargetableTexture, ERHIAccess::Unknown, ERHIAccess::SRVMask));
	}
}
void FProjectedShadowInfo::SetupShadowUniformBuffers(FRHICommandListImmediate& RHICmdList, FScene* Scene, FLightPropagationVolume* LPV)
{
	const ERHIFeatureLevel::Type FeatureLevel = ShadowDepthView->FeatureLevel;
	if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
	{
		FShadowDepthPassUniformParameters ShadowDepthPassParameters;
		SetupShadowDepthPassUniformBuffer(this, RHICmdList, *ShadowDepthView, ShadowDepthPassParameters, LPV);

		if (IsWholeSceneDirectionalShadow() && !bReflectiveShadowmap)
		{
			check(GetShadowDepthType() == CSMShadowDepthType);
			Scene->UniformBuffers.CSMShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
		}

		ShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);

		if (DependentView)
		{
			extern TSet<IPersistentViewUniformBufferExtension*> PersistentViewUniformBufferExtensions;

			for (IPersistentViewUniformBufferExtension* Extension : PersistentViewUniformBufferExtensions)
			{
				Extension->BeginRenderView(DependentView);
			}
		}
	}
	
	// This needs to be done for both mobile and deferred
	UploadDynamicPrimitiveShaderDataForView(RHICmdList, *Scene, *ShadowDepthView);
}

void FProjectedShadowInfo::TransitionCachedShadowmap(FRHICommandListImmediate& RHICmdList, FScene* Scene)
{
	if (CacheMode == SDCM_MovablePrimitivesOnly)
	{
		const FCachedShadowMapData& CachedShadowMapData = Scene->CachedShadowMaps.FindChecked(GetLightSceneInfo().Id);
		if (CachedShadowMapData.bCachedShadowMapHasPrimitives && CachedShadowMapData.ShadowMap.IsValid())
		{
			RHICmdList.Transition(FRHITransitionInfo(CachedShadowMapData.ShadowMap.DepthTarget->GetRenderTargetItem().ShaderResourceTexture, ERHIAccess::Unknown, ERHIAccess::SRVGraphics));
		}
	}
}
void FProjectedShadowInfo::RenderDepth(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch)
{
#if WANTS_DRAW_MESH_EVENTS
	FString EventName;

	if (GetEmitDrawEvents())
	{
		GetShadowTypeNameForDrawEvent(EventName);
		EventName += FString(TEXT(" ")) + FString::FromInt(ResolutionX) + TEXT("x") + FString::FromInt(ResolutionY);
	}

	SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepthActor, *EventName);
#endif

	CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderWholeSceneShadowDepthsTime, bWholeSceneShadow);
	CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderPerObjectShadowDepthsTime, !bWholeSceneShadow);
	QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderShadowDepth);

	RenderDepthInner(RHICmdList, SceneRenderer, BeginShadowRenderPass, bDoParallelDispatch);
}

void FProjectedShadowInfo::RenderDepthInner(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch)
{
	const ERHIFeatureLevel::Type FeatureLevel = ShadowDepthView->FeatureLevel;
	FRHIUniformBuffer* PassUniformBuffer = ShadowDepthPassUniformBuffer;

	const bool bIsWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();

	if (bIsWholeSceneDirectionalShadow)
	{
		// CSM shadow depth cached mesh draw commands are all referencing the same view uniform buffer.  We need to update it before rendering each cascade.
		ShadowDepthView->ViewUniformBuffer.UpdateUniformBufferImmediate(*ShadowDepthView->CachedViewUniformShaderParameters);
		
		if (DependentView)
		{
			extern TSet<IPersistentViewUniformBufferExtension*> PersistentViewUniformBufferExtensions;

			for (IPersistentViewUniformBufferExtension* Extension : PersistentViewUniformBufferExtensions)
			{
				Extension->BeginRenderView(DependentView);
			}
		}
	}

	if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
	{
		FMobileShadowDepthPassUniformParameters ShadowDepthPassParameters;
		SetupShadowDepthPassUniformBuffer(this, RHICmdList, *ShadowDepthView, ShadowDepthPassParameters);
		SceneRenderer->Scene->UniformBuffers.MobileCSMShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
		MobileShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
		PassUniformBuffer = SceneRenderer->Scene->UniformBuffers.MobileCSMShadowDepthPassUniformBuffer;
	}

	FMeshPassProcessorRenderState DrawRenderState(*ShadowDepthView, PassUniformBuffer);
	SetStateForShadowDepth(bReflectiveShadowmap, bOnePassPointLightShadow, DrawRenderState);
	SetStateForView(RHICmdList);

	if (CacheMode == SDCM_MovablePrimitivesOnly)
	{
		// In parallel mode we will not have a renderpass active at this point.
		if (bDoParallelDispatch)
		{
			BeginShadowRenderPass(RHICmdList, false);
		}

		// Copy in depths of static primitives before we render movable primitives
		CopyCachedShadowMap(RHICmdList, DrawRenderState, SceneRenderer, *ShadowDepthView);

		if (bDoParallelDispatch)
		{
			RHICmdList.EndRenderPass();
		}
	}

	if (bDoParallelDispatch)
	{
		check(IsInRenderingThread());
		// Parallel encoding requires its own renderpass.
		check(RHICmdList.IsOutsideRenderPass());

		// parallel version
		bool bFlush = CVarRHICmdFlushRenderThreadTasksShadowPass.GetValueOnRenderThread() > 0
			|| CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0;
		FScopedCommandListWaitForTasks Flusher(bFlush);

		// Dispatch commands
		{
			FShadowParallelCommandListSet ParallelCommandListSet(RHICmdList, *ShadowDepthView, !bFlush, *this, BeginShadowRenderPass);

			ShadowDepthPass.DispatchDraw(&ParallelCommandListSet, RHICmdList);
		}

		// Renderpass must be closed once we get here.
		check(RHICmdList.IsOutsideRenderPass());
	}
	else
	{
		// We must have already opened the renderpass by the time we get here.
		check(RHICmdList.IsInsideRenderPass());

		ShadowDepthPass.DispatchDraw(nullptr, RHICmdList);

		// Renderpass must still be open when we reach here
		check(RHICmdList.IsInsideRenderPass());
	}
}

void FParallelMeshDrawCommandPass::DispatchDraw(FParallelCommandListSet* ParallelCommandListSet, FRHICommandList& RHICmdList) const
{
	TRACE_CPUPROFILER_EVENT_SCOPE(ParallelMdcDispatchDraw);
	if (MaxNumDraws <= 0)
	{
		return;
	}

	FRHIVertexBuffer* PrimitiveIdsBuffer = PrimitiveIdVertexBufferPoolEntry.BufferRHI;
	const int32 BasePrimitiveIdsOffset = 0;

	if (ParallelCommandListSet)
	{
		if (TaskContext.bUseGPUScene)
		{
			// Queue a command on the RHI thread which will upload PrimitiveIdVertexBuffer after finishing FMeshDrawCommandPassSetupTask.
			FRHICommandListImmediate &RHICommandList = GetImmediateCommandList_ForRenderCommand();

			if (TaskEventRef.IsValid())
			{
				RHICommandList.AddDispatchPrerequisite(TaskEventRef);
			}

			RHICommandList.EnqueueLambda([
				VertexBuffer = PrimitiveIdsBuffer,
				VertexBufferData = TaskContext.PrimitiveIdBufferData, 
				VertexBufferDataSize = TaskContext.PrimitiveIdBufferDataSize,
				PrimitiveIdVertexBufferPoolEntry = PrimitiveIdVertexBufferPoolEntry](FRHICommandListImmediate& CmdList)
			{
				// Upload vertex buffer data.
				void* RESTRICT Data = (void* RESTRICT)CmdList.LockVertexBuffer(VertexBuffer, 0, VertexBufferDataSize, RLM_WriteOnly);
				FMemory::Memcpy(Data, VertexBufferData, VertexBufferDataSize);
				CmdList.UnlockVertexBuffer(VertexBuffer);

				FMemory::Free(VertexBufferData);
			});

			RHICommandList.RHIThreadFence(true);

			bPrimitiveIdBufferDataOwnedByRHIThread = true;
		}

		const ENamedThreads::Type RenderThread = ENamedThreads::GetRenderThread();

		FGraphEventArray Prereqs;
		if (ParallelCommandListSet->GetPrereqs())
		{
			Prereqs.Append(*ParallelCommandListSet->GetPrereqs());
		}
		if (TaskEventRef.IsValid())
		{
			Prereqs.Add(TaskEventRef);
		}

		// Distribute work evenly to the available task graph workers based on NumEstimatedDraws.
		// Every task will then adjust it's working range based on FVisibleMeshDrawCommandProcessTask results.
		const int32 NumThreads = FMath::Min<int32>(FTaskGraphInterface::Get().GetNumWorkerThreads(), ParallelCommandListSet->Width);
		const int32 NumTasks = FMath::Min<int32>(NumThreads, FMath::DivideAndRoundUp(MaxNumDraws, ParallelCommandListSet->MinDrawsPerCommandList));
		const int32 NumDrawsPerTask = FMath::DivideAndRoundUp(MaxNumDraws, NumTasks);

		for (int32 TaskIndex = 0; TaskIndex < NumTasks; TaskIndex++)
		{
			const int32 StartIndex = TaskIndex * NumDrawsPerTask;
			const int32 NumDraws = FMath::Min(NumDrawsPerTask, MaxNumDraws - StartIndex);
			checkSlow(NumDraws > 0);

			FRHICommandList* CmdList = ParallelCommandListSet->NewParallelCommandList();

			FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FDrawVisibleMeshCommandsAnyThreadTask>::CreateTask(&Prereqs, RenderThread)
				.ConstructAndDispatchWhenReady(*CmdList, TaskContext.MeshDrawCommands, TaskContext.MinimalPipelineStatePassSet, PrimitiveIdsBuffer, BasePrimitiveIdsOffset, TaskContext.bDynamicInstancing, TaskContext.InstanceFactor, TaskIndex, NumTasks);
			ParallelCommandListSet->AddParallelCommandList(CmdList, AnyThreadCompletionEvent, NumDraws);
		}
	}
	else
	{
		QUICK_SCOPE_CYCLE_COUNTER(STAT_MeshPassDrawImmediate);

		WaitForMeshPassSetupTask();

		if (TaskContext.bUseGPUScene)
		{
			// Can immediately upload vertex buffer data, as there is no parallel draw task.
			void* RESTRICT Data = RHILockVertexBuffer(PrimitiveIdVertexBufferPoolEntry.BufferRHI, 0, TaskContext.PrimitiveIdBufferDataSize, RLM_WriteOnly);
			FMemory::Memcpy(Data, TaskContext.PrimitiveIdBufferData, TaskContext.PrimitiveIdBufferDataSize);
			RHIUnlockVertexBuffer(PrimitiveIdVertexBufferPoolEntry.BufferRHI);
		}

		SubmitMeshDrawCommandsRange(TaskContext.MeshDrawCommands, TaskContext.MinimalPipelineStatePassSet, PrimitiveIdsBuffer, BasePrimitiveIdsOffset, TaskContext.bDynamicInstancing, 0, TaskContext.MeshDrawCommands.Num(), TaskContext.InstanceFactor, RHICmdList);
	}
}

猜你喜欢

转载自blog.csdn.net/sh15285118586/article/details/124552681