/**
 * Initialize scene's views.
 * Check visibility, sort translucent items, etc.
 */
void FForwardShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList)
{
	SCOPED_DRAW_EVENT(RHICmdList, InitViews);

	SCOPE_CYCLE_COUNTER(STAT_InitViewsTime);

	FILCUpdatePrimTaskData ILCTaskData;
	PreVisibilityFrameSetup(RHICmdList);
	ComputeViewVisibility(RHICmdList);
	PostVisibilityFrameSetup(ILCTaskData);

	bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows && GetShadowQuality() > 0;

	if (bDynamicShadows && !IsSimpleDynamicLightingEnabled())
	{
		// Setup dynamic shadows.
		InitDynamicShadows(RHICmdList);		
	}

	// if we kicked off ILC update via task, wait and finalize.
	if (ILCTaskData.TaskRef.IsValid())
	{
		Scene->IndirectLightingCache.FinalizeCacheUpdates(Scene, *this, ILCTaskData);
	}

	// initialize per-view uniform buffer.  Pass in shadow info as necessary.
	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		const TArray<FProjectedShadowInfo*, SceneRenderingAllocator>* DirectionalLightShadowInfo = nullptr;

		FViewInfo& ViewInfo = Views[ViewIndex];
		FScene* Scene = (FScene*)ViewInfo.Family->Scene;
		if (bDynamicShadows && Scene->SimpleDirectionalLight)
		{
			int32 LightId = Scene->SimpleDirectionalLight->Id;
			if (VisibleLightInfos.IsValidIndex(LightId))
			{
				const FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightId];
				if (VisibleLightInfo.AllProjectedShadows.Num() > 0)
				{
					DirectionalLightShadowInfo = &VisibleLightInfo.AllProjectedShadows;
				}
			}
		}

		// Initialize the view's RHI resources.
		Views[ViewIndex].InitRHIResources(DirectionalLightShadowInfo);
	}

	// Now that the indirect lighting cache is updated, we can update the primitive precomputed lighting buffers.
	UpdatePrimitivePrecomputedLightingBuffers();
	
	OnStartFrame();
}
/**
 * Initialize scene's views.
 * Check visibility, sort translucent items, etc.
 */
void FForwardShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList)
{
	SCOPED_DRAW_EVENT(RHICmdList, InitViews);

	SCOPE_CYCLE_COUNTER(STAT_InitViewsTime);

	PreVisibilityFrameSetup(RHICmdList);
	ComputeViewVisibility(RHICmdList);
	PostVisibilityFrameSetup();

	bool bDynamicShadows = ViewFamily.EngineShowFlags.DynamicShadows && GetShadowQuality() > 0;

	if (bDynamicShadows && !IsSimpleDynamicLightingEnabled())
	{
		// Setup dynamic shadows.
		InitDynamicShadows(RHICmdList);		
	}

	// initialize per-view uniform buffer.  Pass in shadow info as necessary.
	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		const TArray<FProjectedShadowInfo*, SceneRenderingAllocator>* DirectionalLightShadowInfo = nullptr;

		FViewInfo& ViewInfo = Views[ViewIndex];
		FScene* Scene = (FScene*)ViewInfo.Family->Scene;
		if (bDynamicShadows && Scene->SimpleDirectionalLight)
		{
			int32 LightId = Scene->SimpleDirectionalLight->Id;
			if (VisibleLightInfos.IsValidIndex(LightId))
			{
				const FVisibleLightInfo& VisibleLightInfo = VisibleLightInfos[LightId];
				if (VisibleLightInfo.AllProjectedShadows.Num() > 0)
				{
					DirectionalLightShadowInfo = &VisibleLightInfo.AllProjectedShadows;
				}
			}
		}

		// Initialize the view's RHI resources.
		Views[ViewIndex].InitRHIResources(DirectionalLightShadowInfo);
	}

	OnStartFrame();
}
// @return 0:off, 0..4
static uint32 ComputeAmbientOcclusionPassCount(FPostprocessContext& Context)
{
	uint32 Ret = 0;

	bool bEnabled = true;

	if(!IsLpvIndirectPassRequired(Context))
	{
		bEnabled = Context.View.FinalPostProcessSettings.AmbientOcclusionIntensity > 0 
			&& Context.View.FinalPostProcessSettings.AmbientOcclusionRadius >= 0.1f 
			&& (IsBasePassAmbientOcclusionRequired(Context) || IsAmbientCubemapPassRequired(Context) || IsReflectionEnvironmentActive(Context) || IsSkylightActive(Context) || Context.View.Family->EngineShowFlags.VisualizeBuffer )
			&& !IsSimpleDynamicLightingEnabled();
	}

	if(bEnabled)
	{
		static const auto ICVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AmbientOcclusionLevels"));
		Ret = FMath::Clamp(ICVar->GetValueOnRenderThread(), 0, 4);
	}

	return Ret;
}
static bool IsBasePassAmbientOcclusionRequired(FPostprocessContext& Context)
{
	// the BaseAO pass is only worth with some AO
	return Context.View.FinalPostProcessSettings.AmbientOcclusionStaticFraction >= 1 / 100.0f && !IsSimpleDynamicLightingEnabled();
}
static bool IsReflectionEnvironmentActive(FPostprocessContext& Context)
{
	FScene* Scene = (FScene*)Context.View.Family->Scene;

	// LPV & Screenspace Reflections : Reflection Environment active if either LPV (assumed true if this was called), Reflection Captures or SSR active

	bool IsReflectingEnvironment = Context.View.Family->EngineShowFlags.ReflectionEnvironment;
	bool HasReflectionCaptures = (Scene->ReflectionSceneData.RegisteredReflectionCaptures.Num() > 0);
	bool HasSSR = Context.View.Family->EngineShowFlags.ScreenSpaceReflections;

	return (Scene->GetFeatureLevel() == ERHIFeatureLevel::SM5 && IsReflectingEnvironment && (HasReflectionCaptures || HasSSR) && !IsSimpleDynamicLightingEnabled());
}
static bool IsAmbientCubemapPassRequired(FPostprocessContext& Context)
{
	FScene* Scene = (FScene*)Context.View.Family->Scene;

	return Context.View.FinalPostProcessSettings.ContributingCubemaps.Num() != 0 && !IsSimpleDynamicLightingEnabled();
}
void FCompositionLighting::ProcessAfterLighting(FRHICommandListImmediate& RHICmdList, FViewInfo& View)
{
	check(IsInRenderingThread());
	FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);

	
	GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDiffuse);
	GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapNormal);
	GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, SceneContext.ReflectiveShadowMapDepth);

	{
		FMemMark Mark(FMemStack::Get());
		FRenderingCompositePassContext CompositeContext(RHICmdList, View);
		FPostprocessContext Context(CompositeContext.Graph, View);
		FRenderingCompositeOutputRef AmbientOcclusion;

		// Screen Space Subsurface Scattering
		{
			float Radius = CVarSSSScale.GetValueOnRenderThread();

			bool bSimpleDynamicLighting = IsSimpleDynamicLightingEnabled();

			bool bScreenSpaceSubsurfacePassNeeded = (View.ShadingModelMaskInView & (1 << MSM_SubsurfaceProfile)) != 0;
			if (bScreenSpaceSubsurfacePassNeeded && Radius > 0 && !bSimpleDynamicLighting && View.Family->EngineShowFlags.SubsurfaceScattering &&
				//@todo-rco: Remove this when we fix the cross-compiler
				!IsOpenGLPlatform(View.GetShaderPlatform()))
			{
				// can be optimized out if we don't do split screen/stereo rendering (should be done after we some post process refactoring)
				FRenderingCompositePass* PassExtractSpecular = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceExtractSpecular());
				PassExtractSpecular->SetInput(ePId_Input0, Context.FinalOutput);

				FRenderingCompositePass* PassSetup = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceSetup(View));
				PassSetup->SetInput(ePId_Input0, Context.FinalOutput);

				FRenderingCompositePass* Pass0 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(0));
				Pass0->SetInput(ePId_Input0, PassSetup);

				FRenderingCompositePass* Pass1 = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurface(1));
				Pass1->SetInput(ePId_Input0, Pass0);
				Pass1->SetInput(ePId_Input1, PassSetup);

				// full res composite pass, no blurring (Radius=0)
				FRenderingCompositePass* RecombinePass = Context.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSubsurfaceRecombine());
				RecombinePass->SetInput(ePId_Input0, Pass1);
				RecombinePass->SetInput(ePId_Input1, PassExtractSpecular);
				
				SCOPED_DRAW_EVENT(RHICmdList, CompositionLighting_SSSSS);

				CompositeContext.Process(RecombinePass, TEXT("CompositionLighting_SSSSS"));
			}
		}

		// The graph setup should be finished before this line ----------------------------------------

		SCOPED_DRAW_EVENT(RHICmdList, CompositionAfterLighting);

		// we don't replace the final element with the scenecolor because this is what those passes should do by themself

		CompositeContext.Process(Context.FinalOutput.GetPass(), TEXT("CompositionLighting"));
	}

	// We only release the after the last view was processed (SplitScreen)
	if(View.Family->Views[View.Family->Views.Num() - 1] == &View)
	{
		// The RT should be released as early as possible to allow sharing of that memory for other purposes.
		// This becomes even more important with some limited VRam (XBoxOne).
		SceneContext.SetLightAttenuation(0);
	}
}