Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.cpp
T

1474 lines
59 KiB
C++
Raw Normal View History

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
DeferredShadingRenderer.cpp: Top level rendering loop for deferred shading
=============================================================================*/
#include "RendererPrivate.h"
#include "Engine.h"
#include "ScenePrivate.h"
#include "ScreenRendering.h"
#include "SceneFilterRendering.h"
2015-04-09 19:14:28 -04:00
#include "ScreenSpaceReflections.h"
#include "VisualizeTexture.h"
#include "CompositionLighting.h"
#include "FXSystem.h"
#include "OneColorShader.h"
#include "CompositionLighting/PostProcessDeferredDecals.h"
#include "LightPropagationVolume.h"
#include "DeferredShadingRenderer.h"
#include "SceneUtils.h"
2014-09-18 15:13:07 -04:00
#include "DistanceFieldSurfaceCacheLighting.h"
#include "GlobalDistanceField.h"
2014-09-03 07:26:17 -04:00
#include "PostProcess/PostProcessing.h"
#include "DistanceFieldAtlas.h"
#include "EngineModule.h"
2015-07-24 15:06:10 -04:00
#include "IHeadMountedDisplay.h"
#include "GPUSkinCache.h"
TAutoConsoleVariable<int32> CVarEarlyZPass(
TEXT("r.EarlyZPass"),
3,
TEXT("Whether to use a depth only pass to initialize Z culling for the base pass. Cannot be changed at runtime.\n")
TEXT("Note: also look at r.EarlyZPassMovable\n")
TEXT(" 0: off\n")
TEXT(" 1: good occluders only: not masked, and large on screen\n")
TEXT(" 2: all opaque (including masked)\n")
TEXT(" x: use built in heuristic (default is 3)"),
ECVF_Scalability);
int32 GEarlyZPassMovable = 0;
/** Affects static draw lists so must reload level to propagate. */
static FAutoConsoleVariableRef CVarEarlyZPassMovable(
TEXT("r.EarlyZPassMovable"),
GEarlyZPassMovable,
TEXT("Whether to render movable objects into the depth only pass. Movable objects are typically not good occluders so this defaults to off.\n")
TEXT("Note: also look at r.EarlyZPass"),
ECVF_RenderThreadSafe | ECVF_Scalability
);
static TAutoConsoleVariable<int32> CVarStencilForLODDither(
TEXT("r.StencilForLODDither"),
0,
TEXT("Whether to use stencil tests in the prepass, and depth-equal tests in the base pass to implement LOD dithering.\n")
TEXT("If disabled, LOD dithering will be done through clip() instructions in the prepass and base pass, which disables EarlyZ.\n")
TEXT("Forces a full prepass when enabled."),
ECVF_RenderThreadSafe | ECVF_ReadOnly);
TAutoConsoleVariable<int32> CVarCustomDepthOrder(
TEXT("r.CustomDepth.Order"),
1,
TEXT("When CustomDepth (and CustomStencil) is getting rendered\n")
TEXT(" 0: Before GBuffer (can be more efficient with AsyncCompute, allows using it in DBuffer pass, no GBuffer blending decals allow GBuffer compression)\n")
TEXT(" 1: After Base Pass (default)"),
ECVF_RenderThreadSafe);
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
static TAutoConsoleVariable<int32> CVarVisualizeTexturePool(
TEXT("r.VisualizeTexturePool"),
0,
TEXT("Allows to enable the visualize the texture pool (currently only on console).\n")
TEXT(" 0: off (default)\n")
TEXT(" 1: on"),
ECVF_Cheat | ECVF_RenderThreadSafe);
#endif
static TAutoConsoleVariable<int32> CVarClearCoatNormal(
TEXT("r.ClearCoatNormal"),
0,
TEXT("0 to disable clear coat normal.\n")
TEXT(" 0: off\n")
TEXT(" 1: on"),
ECVF_ReadOnly);
static TAutoConsoleVariable<int32> CVarFXSystemPreRenderAfterPrepass(
TEXT("r.FXSystemPreRenderAfterPrepass"),
0,
TEXT("If > 0, then do the FX prerender after the prepass. This improves pipelining for greater performance. Experiemental option."),
ECVF_RenderThreadSafe
);
int32 GbEnableAsyncComputeTranslucencyLightingVolumeClear = 1;
static FAutoConsoleVariableRef CVarEnableAsyncComputeTranslucencyLightingVolumeClear(
TEXT("r.EnableAsyncComputeTranslucencyLightingVolumeClear"),
GbEnableAsyncComputeTranslucencyLightingVolumeClear,
TEXT("Whether to clear the translucency lighting volume using async compute.\n"),
ECVF_RenderThreadSafe | ECVF_Scalability
);
2015-12-02 16:42:06 -05:00
DECLARE_CYCLE_STAT(TEXT("PostInitViews FlushDel"), STAT_PostInitViews_FlushDel, STATGROUP_InitViews);
DECLARE_CYCLE_STAT(TEXT("InitViews Intentional Stall"), STAT_InitViews_Intentional_Stall, STATGROUP_InitViews);
DEFINE_STAT(STAT_FDeferredShadingSceneRenderer_AsyncSortBasePassStaticData);
2015-12-02 16:42:06 -05:00
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer UpdateDownsampledDepthSurface"), STAT_FDeferredShadingSceneRenderer_UpdateDownsampledDepthSurface, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer Render Init"), STAT_FDeferredShadingSceneRenderer_Render_Init, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer Render ServiceLocalQueue"), STAT_FDeferredShadingSceneRenderer_Render_ServiceLocalQueue, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer DistanceFieldAO Init"), STAT_FDeferredShadingSceneRenderer_DistanceFieldAO_Init, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer FGlobalDynamicVertexBuffer Commit"), STAT_FDeferredShadingSceneRenderer_FGlobalDynamicVertexBuffer_Commit, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer MotionBlurStartFrame"), STAT_FDeferredShadingSceneRenderer_MotionBlurStartFrame, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer FXSystem PreRender"), STAT_FDeferredShadingSceneRenderer_FXSystem_PreRender, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer AllocGBufferTargets"), STAT_FDeferredShadingSceneRenderer_AllocGBufferTargets, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer ClearLPVs"), STAT_FDeferredShadingSceneRenderer_ClearLPVs, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer DBuffer"), STAT_FDeferredShadingSceneRenderer_DBuffer, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer SetAndClearViewGBuffer"), STAT_FDeferredShadingSceneRenderer_SetAndClearViewGBuffer, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer ClearGBufferAtMaxZ"), STAT_FDeferredShadingSceneRenderer_ClearGBufferAtMaxZ, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer ResolveDepth After Basepass"), STAT_FDeferredShadingSceneRenderer_ResolveDepth_After_Basepass, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer Resolve After Basepass"), STAT_FDeferredShadingSceneRenderer_Resolve_After_Basepass, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer FXSystem PostRenderOpaque"), STAT_FDeferredShadingSceneRenderer_FXSystem_PostRenderOpaque, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer AfterBasePass"), STAT_FDeferredShadingSceneRenderer_AfterBasePass, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer Lighting"), STAT_FDeferredShadingSceneRenderer_Lighting, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderLightShaftOcclusion"), STAT_FDeferredShadingSceneRenderer_RenderLightShaftOcclusion, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderAtmosphere"), STAT_FDeferredShadingSceneRenderer_RenderAtmosphere, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderFog"), STAT_FDeferredShadingSceneRenderer_RenderFog, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderLightShaftBloom"), STAT_FDeferredShadingSceneRenderer_RenderLightShaftBloom, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer UpdateMotionBlurCache"), STAT_FDeferredShadingSceneRenderer_UpdateMotionBlurCache, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("DeferredShadingSceneRenderer RenderFinish"), STAT_FDeferredShadingSceneRenderer_RenderFinish, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("OcclusionSubmittedFence Dispatch"), STAT_OcclusionSubmittedFence_Dispatch, STATGROUP_SceneRendering);
DECLARE_CYCLE_STAT(TEXT("OcclusionSubmittedFence Wait"), STAT_OcclusionSubmittedFence_Wait, STATGROUP_SceneRendering);
DECLARE_FLOAT_COUNTER_STAT(TEXT("Postprocessing"), Stat_GPU_Postprocessing, STATGROUP_GPU);
DECLARE_FLOAT_COUNTER_STAT(TEXT("HZB"), Stat_GPU_HZB, STATGROUP_GPU);
DECLARE_FLOAT_COUNTER_STAT(TEXT("[unaccounted]"), Stat_GPU_Unaccounted, STATGROUP_GPU);
bool ShouldForceFullDepthPass(ERHIFeatureLevel::Type FeatureLevel)
{
static IConsoleVariable* CDBufferVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DBuffer"));
bool bDBufferAllowed = CDBufferVar ? CDBufferVar->GetInt() != 0 : false;
static const auto StencilLODDitherCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.StencilForLODDither"));
bool bStencilLODDither = StencilLODDitherCVar->GetValueOnAnyThread() != 0;
// Note: ShouldForceFullDepthPass affects which static draw lists meshes go into, so nothing it depends on can change at runtime, unless you do a FGlobalComponentRecreateRenderStateContext to propagate the cvar change
return bDBufferAllowed || bStencilLODDither || IsForwardShadingEnabled(FeatureLevel);
}
const TCHAR* GetDepthPassReason(bool bDitheredLODTransitionsUseStencil, ERHIFeatureLevel::Type FeatureLevel)
{
if (IsForwardShadingEnabled(FeatureLevel))
{
return TEXT("(Forced by ForwardShading)");
}
static IConsoleVariable* CDBufferVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DBuffer"));
bool bDBufferAllowed = CDBufferVar ? CDBufferVar->GetInt() != 0 : false;
if (bDBufferAllowed)
{
return TEXT("(Forced by DBuffer)");
}
if (bDitheredLODTransitionsUseStencil)
{
return TEXT("(Forced by StencilLODDither)");
}
return TEXT("");
}
2015-12-02 16:42:06 -05:00
/*-----------------------------------------------------------------------------
FDeferredShadingSceneRenderer
-----------------------------------------------------------------------------*/
FDeferredShadingSceneRenderer::FDeferredShadingSceneRenderer(const FSceneViewFamily* InViewFamily,FHitProxyConsumer* HitProxyConsumer)
: FSceneRenderer(InViewFamily, HitProxyConsumer)
, EarlyZPassMode(DDM_NonMaskedOnly)
, bEarlyZPassMovable(false)
{
if (FPlatformProperties::SupportsWindowedMode())
{
// Use a depth only pass if we are using full blown HQ lightmaps
// Otherwise base pass pixel shaders will be cheap and there will be little benefit to rendering a depth only pass
2014-07-24 05:23:50 -04:00
if (AllowHighQualityLightmaps(FeatureLevel) || !ViewFamily.EngineShowFlags.Lighting)
{
EarlyZPassMode = DDM_None;
}
}
// developer override, good for profiling, can be useful as project setting
{
const int32 CVarValue = CVarEarlyZPass.GetValueOnGameThread();
switch(CVarValue)
{
case 0: EarlyZPassMode = DDM_None; break;
case 1: EarlyZPassMode = DDM_NonMaskedOnly; break;
case 2: EarlyZPassMode = DDM_AllOccluders; break;
case 3: break; // Note: 3 indicates "default behavior" and does not specify an override
}
}
// Shader complexity requires depth only pass to display masked material cost correctly
if (ViewFamily.UseDebugViewPS() && ViewFamily.GetDebugViewShaderMode() != DVSM_MaterialTexCoordScalesAnalysis)
{
EarlyZPassMode = DDM_AllOpaque;
}
// Warning: EarlyZPass logic is mirrored in FStaticMesh::AddToDrawLists
bEarlyZPassMovable = GEarlyZPassMovable != 0;
static const auto StencilLODDitherCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.StencilForLODDither"));
bDitheredLODTransitionsUseStencil = StencilLODDitherCVar->GetValueOnAnyThread() != 0;
if (ShouldForceFullDepthPass(FeatureLevel))
{
// DBuffer decals and stencil LOD dithering force a full prepass
EarlyZPassMode = DDM_AllOccluders;
bEarlyZPassMovable = true;
}
}
extern FGlobalBoundShaderState GClearMRTBoundShaderState[8];
float GetSceneColorClearAlpha()
{
// Scene color alpha is used during scene captures and planar reflections. 1 indicates background should be shown, 0 indicates foreground is fully present.
return 1.0f;
}
/**
* Clears view where Z is still at the maximum value (ie no geometry rendered)
*/
void FDeferredShadingSceneRenderer::ClearGBufferAtMaxZ(FRHICommandList& RHICmdList)
{
// Assumes BeginRenderingSceneColor() has been called before this function
SCOPED_DRAW_EVENT(RHICmdList, ClearGBufferAtMaxZ);
// Clear the G Buffer render targets
const bool bClearBlack = Views[0].Family->EngineShowFlags.ShaderComplexity || Views[0].Family->EngineShowFlags.StationaryLightOverlap;
const float ClearAlpha = GetSceneColorClearAlpha();
const FLinearColor ClearColor = bClearBlack ? FLinearColor(0, 0, 0, ClearAlpha) : FLinearColor(Views[0].BackgroundColor.R, Views[0].BackgroundColor.G, Views[0].BackgroundColor.B, ClearAlpha);
// Same clear color from RHIClearMRT
FLinearColor ClearColors[MaxSimultaneousRenderTargets] =
{ClearColor, FLinearColor(0.5f,0.5f,0.5f,0), FLinearColor(0,0,0,1), FLinearColor(0,0,0,0), FLinearColor(0,1,1,1), FLinearColor(1,1,1,1), FLinearColor::Transparent, FLinearColor::Transparent};
uint32 NumActiveRenderTargets = FSceneRenderTargets::Get(RHICmdList).GetNumGBufferTargets();
2014-08-28 06:22:54 -04:00
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
TShaderMapRef<TOneColorVS<true> > VertexShader(ShaderMap);
FOneColorPS* PixelShader = NULL;
// Assume for now all code path supports SM4, otherwise render target numbers are changed
switch(NumActiveRenderTargets)
{
case 5:
{
2014-08-28 06:22:54 -04:00
TShaderMapRef<TOneColorPixelShaderMRT<5> > MRTPixelShader(ShaderMap);
PixelShader = *MRTPixelShader;
}
break;
case 6:
{
2014-08-28 06:22:54 -04:00
TShaderMapRef<TOneColorPixelShaderMRT<6> > MRTPixelShader(ShaderMap);
PixelShader = *MRTPixelShader;
}
break;
default:
case 1:
{
2014-08-28 06:22:54 -04:00
TShaderMapRef<TOneColorPixelShaderMRT<1> > MRTPixelShader(ShaderMap);
PixelShader = *MRTPixelShader;
}
break;
}
2014-08-19 10:41:34 -04:00
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, GClearMRTBoundShaderState[NumActiveRenderTargets - 1], GetVertexDeclarationFVector4(), *VertexShader, PixelShader);
// Opaque rendering, depth test but no depth writes
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendStateWriteMask<>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
// Clear each viewport by drawing background color at MaxZ depth
for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("ClearView%d"), ViewIndex);
FViewInfo& View = Views[ViewIndex];
// Set viewport for this view
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1);
// Setup PS
PixelShader->SetColors(RHICmdList, ClearColors, NumActiveRenderTargets);
// Render quad
2015-03-06 15:13:38 -05:00
static const FVector4 ClearQuadVertices[4] =
{
FVector4( -1.0f, 1.0f, (float)ERHIZBuffer::FarPlane, 1.0f),
FVector4( 1.0f, 1.0f, (float)ERHIZBuffer::FarPlane, 1.0f ),
FVector4( -1.0f, -1.0f, (float)ERHIZBuffer::FarPlane, 1.0f ),
FVector4( 1.0f, -1.0f, (float)ERHIZBuffer::FarPlane, 1.0f )
2015-03-06 15:13:38 -05:00
};
DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, ClearQuadVertices, sizeof(ClearQuadVertices[0]));
}
}
/** Render the TexturePool texture */
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
void FDeferredShadingSceneRenderer::RenderVisualizeTexturePool(FRHICommandListImmediate& RHICmdList)
{
TRefCountPtr<IPooledRenderTarget> VisualizeTexturePool;
/** Resolution for the texture pool visualizer texture. */
enum
{
TexturePoolVisualizerSizeX = 280,
TexturePoolVisualizerSizeY = 140,
};
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(TexturePoolVisualizerSizeX, TexturePoolVisualizerSizeY), PF_B8G8R8A8, FClearValueBinding::None, TexCreate_None, TexCreate_None, false));
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, VisualizeTexturePool, TEXT("VisualizeTexturePool"));
uint32 Pitch;
FColor* TextureData = (FColor*)RHICmdList.LockTexture2D((FTexture2DRHIRef&)VisualizeTexturePool->GetRenderTargetItem().ShaderResourceTexture, 0, RLM_WriteOnly, Pitch, false);
if(TextureData)
{
// clear with grey to get reliable background color
FMemory::Memset(TextureData, 0x88, TexturePoolVisualizerSizeX * TexturePoolVisualizerSizeY * 4);
RHICmdList.GetTextureMemoryVisualizeData(TextureData, TexturePoolVisualizerSizeX, TexturePoolVisualizerSizeY, Pitch, 4096);
}
RHICmdList.UnlockTexture2D((FTexture2DRHIRef&)VisualizeTexturePool->GetRenderTargetItem().ShaderResourceTexture, 0, false);
FIntPoint RTExtent = FSceneRenderTargets::Get(RHICmdList).GetBufferSizeXY();
FVector2D Tex00 = FVector2D(0, 0);
FVector2D Tex11 = FVector2D(1, 1);
//todo VisualizeTexture(*VisualizeTexturePool, ViewFamily.RenderTarget, FIntRect(0, 0, RTExtent.X, RTExtent.Y), RTExtent, 1.0f, 0.0f, 0.0f, Tex00, Tex11, 1.0f, false);
}
#endif
/**
* Finishes the view family rendering.
*/
void FDeferredShadingSceneRenderer::RenderFinish(FRHICommandListImmediate& RHICmdList)
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
{
if(CVarVisualizeTexturePool.GetValueOnRenderThread())
{
RenderVisualizeTexturePool(RHICmdList);
}
}
#endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (GEnableGPUSkinCache)
{
GGPUSkinCache.TransitionToWriteable(RHICmdList);
}
FSceneRenderer::RenderFinish(RHICmdList);
2014-05-06 17:24:57 -04:00
// Some RT should be released as early as possible to allow sharing of that memory for other purposes.
// SceneColor is be released in tone mapping, if not we want to get access to the HDR scene color after this pass so we keep it.
// This becomes even more important with some limited VRam (XBoxOne).
FSceneRenderTargets::Get(RHICmdList).SetLightAttenuation(0);
}
2015-01-09 20:56:36 -05:00
void BuildHZB( FRHICommandListImmediate& RHICmdList, FViewInfo& View );
/**
* Renders the view family.
*/
DEFINE_STAT(STAT_CLM_PrePass);
DECLARE_CYCLE_STAT(TEXT("FXPreRender"), STAT_CLM_FXPreRender, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterPrePass"), STAT_CLM_AfterPrePass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("BasePass"), STAT_CLM_BasePass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterBasePass"), STAT_CLM_AfterBasePass, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("Lighting"), STAT_CLM_Lighting, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterLighting"), STAT_CLM_AfterLighting, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("Translucency"), STAT_CLM_Translucency, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("RenderDistortion"), STAT_CLM_RenderDistortion, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterTranslucency"), STAT_CLM_AfterTranslucency, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("RenderDistanceFieldLighting"), STAT_CLM_RenderDistanceFieldLighting, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("LightShaftBloom"), STAT_CLM_LightShaftBloom, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("PostProcessing"), STAT_CLM_PostProcessing, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("Velocity"), STAT_CLM_Velocity, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterVelocity"), STAT_CLM_AfterVelocity, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("RenderFinish"), STAT_CLM_RenderFinish, STATGROUP_CommandListMarkers);
DECLARE_CYCLE_STAT(TEXT("AfterFrame"), STAT_CLM_AfterFrame, STATGROUP_CommandListMarkers);
2015-07-01 10:40:13 -04:00
FGraphEventRef FDeferredShadingSceneRenderer::OcclusionSubmittedFence[FOcclusionQueryHelpers::MaxBufferedOcclusionFrames];
FGraphEventRef FDeferredShadingSceneRenderer::TranslucencyTimestampQuerySubmittedFence[FOcclusionQueryHelpers::MaxBufferedOcclusionFrames + 1];
/**
* Returns true if the depth Prepass needs to run
*/
static FORCEINLINE bool NeedsPrePass(const FDeferredShadingSceneRenderer* Renderer)
{
return (RHIHasTiledGPU(Renderer->ViewFamily.GetShaderPlatform()) == false) &&
(Renderer->EarlyZPassMode != DDM_None || Renderer->bEarlyZPassMovable != 0);
}
2014-10-27 20:23:51 -04:00
static void SetAndClearViewGBuffer(FRHICommandListImmediate& RHICmdList, FViewInfo& View, bool bClearDepth)
{
// if we didn't to the prepass above, then we will need to clear now, otherwise, it's already been cleared and rendered to
ERenderTargetLoadAction DepthLoadAction = bClearDepth ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad;
const bool bClearBlack = View.Family->EngineShowFlags.ShaderComplexity || View.Family->EngineShowFlags.StationaryLightOverlap;
const float ClearAlpha = GetSceneColorClearAlpha();
const FLinearColor ClearColor = bClearBlack ? FLinearColor(0, 0, 0, ClearAlpha) : FLinearColor(View.BackgroundColor.R, View.BackgroundColor.G, View.BackgroundColor.B, ClearAlpha);
2014-10-27 20:23:51 -04:00
// clearing the GBuffer
FSceneRenderTargets::Get(RHICmdList).BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::EClear, DepthLoadAction, View.Family->EngineShowFlags.ShaderComplexity, ClearColor);
2014-10-27 20:23:51 -04:00
}
static TAutoConsoleVariable<int32> CVarOcclusionQueryLocation(
TEXT("r.OcclusionQueryLocation"),
0,
TEXT("Controls when occlusion queries are rendered. Rendering before the base pass may give worse occlusion (because not all occluders generally render in the earlyzpass). ")
TEXT("However, it may reduce CPU waiting for query result stalls on some platforms and increase overall performance.")
TEXT("0: After BasePass.")
TEXT("1: After EarlyZPass, but before BasePass."));
void FDeferredShadingSceneRenderer::RenderOcclusion(FRHICommandListImmediate& RHICmdList, bool bRenderQueries, bool bRenderHZB)
{
if (bRenderQueries || bRenderHZB)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_HZB);
{
// Update the quarter-sized depth buffer with the current contents of the scene depth texture.
// This needs to happen before occlusion tests, which makes use of the small depth buffer.
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_UpdateDownsampledDepthSurface);
UpdateDownsampledDepthSurface(RHICmdList);
}
2015-04-09 19:14:28 -04:00
// Issue occlusion queries
// This is done after the downsampled depth buffer is created so that it can be used for issuing queries
BeginOcclusionTests(RHICmdList, bRenderQueries);
if (bRenderHZB)
{
RHICmdList.TransitionResource( EResourceTransitionAccess::EReadable, SceneContext.GetSceneDepthSurface() );
2015-04-09 19:14:28 -04:00
static const auto ICVarAO = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AmbientOcclusionLevels"));
static const auto ICVarHZBOcc = IConsoleManager::Get().FindConsoleVariable(TEXT("r.HZBOcclusion"));
bool bSSAO = ICVarAO->GetValueOnRenderThread() != 0;
bool bHZBOcclusion = ICVarHZBOcc->GetInt() != 0;
2015-04-09 19:14:28 -04:00
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
FViewInfo& View = Views[ViewIndex];
FSceneViewState* ViewState = (FSceneViewState*)View.State;
2015-04-09 19:14:28 -04:00
const uint32 bSSR = ShouldRenderScreenSpaceReflections( View );
if (bSSAO || bHZBOcclusion || bSSR)
2015-04-09 19:14:28 -04:00
{
BuildHZB(RHICmdList, Views[ViewIndex]);
}
if (bHZBOcclusion && ViewState && ViewState->HZBOcclusionTests.GetNum() != 0)
{
check(ViewState->HZBOcclusionTests.IsValidFrame(ViewState->OcclusionFrameCounter));
SCOPED_DRAW_EVENT(RHICmdList, HZB);
ViewState->HZBOcclusionTests.Submit(RHICmdList, View);
}
}
//async ssao only requires HZB and depth as inputs so get started ASAP
if (GCompositionLighting.CanProcessAsyncSSAO(Views))
{
GCompositionLighting.ProcessAsyncSSAO(RHICmdList, Views);
}
}
2015-04-22 14:16:01 -04:00
// Hint to the RHI to submit commands up to this point to the GPU if possible. Can help avoid CPU stalls next frame waiting
// for these query results on some platforms.
RHICmdList.SubmitCommandsHint();
if (bRenderQueries && GRHIThread)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_OcclusionSubmittedFence_Dispatch);
int32 NumFrames = FOcclusionQueryHelpers::GetNumBufferedFrames();
for (int32 Dest = 1; Dest < NumFrames; Dest++)
{
CA_SUPPRESS(6385);
OcclusionSubmittedFence[Dest] = OcclusionSubmittedFence[Dest - 1];
}
OcclusionSubmittedFence[0] = RHICmdList.RHIThreadFence();
RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);
}
}
}
// The render thread is involved in sending stuff to the RHI, so we will periodically service that queue
void ServiceLocalQueue()
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Render_ServiceLocalQueue);
FTaskGraphInterface::Get().ProcessThreadUntilIdle(ENamedThreads::RenderThread_Local);
}
// @return 0/1
static int32 GetCustomDepthPassLocation()
{
return FMath::Clamp(CVarCustomDepthOrder.GetValueOnRenderThread(), 0, 1);
}
extern bool IsLpvIndirectPassRequired(const FViewInfo& View);
2015-08-03 11:44:45 -04:00
static TAutoConsoleVariable<float> CVarStallInitViews(
TEXT("CriticalPathStall.AfterInitViews"),
0.0f,
TEXT("Sleep for the given time after InitViews. Time is given in ms. This is a debug option used for critical path analysis and forcing a change in the critical path."));
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
//make sure all the targets we're going to use will be safely writable.
GRenderTargetPool.TransitionTargetsWritable(RHICmdList);
// this way we make sure the SceneColor format is the correct one and not the one from the end of frame before
SceneContext.ReleaseSceneColor();
bool bDBuffer = IsDBufferEnabled();
if (GRHIThread)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_OcclusionSubmittedFence_Wait);
int32 BlockFrame = FOcclusionQueryHelpers::GetNumBufferedFrames() - 1;
FRHICommandListExecutor::WaitOnRHIThreadFence(OcclusionSubmittedFence[BlockFrame]);
OcclusionSubmittedFence[BlockFrame] = nullptr;
}
if (!ViewFamily.EngineShowFlags.Rendering)
{
return;
}
SCOPED_DRAW_EVENT(RHICmdList, Scene);
// Anything rendered inside Render() which isn't accounted for will fall into this stat
// This works because child stat events do not contribute to their parents' times (see GPU_STATS_CHILD_TIMES_INCLUDED)
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Unaccounted);
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Render_Init);
// Initialize global system textures (pass-through if already initialized).
GSystemTextures.InitializeTextures(RHICmdList, FeatureLevel);
// Allocate the maximum scene render target space for the current view family.
SceneContext.Allocate(RHICmdList, ViewFamily);
}
FGraphEventArray SortEvents;
FILCUpdatePrimTaskData ILCTaskData;
// Find the visible primitives.
bool bDoInitViewAftersPrepass = InitViews(RHICmdList, ILCTaskData, SortEvents);
TGuardValue<bool> LockDrawLists(GDrawListsLocked, true);
2015-08-03 11:44:45 -04:00
#if !UE_BUILD_SHIPPING
if (CVarStallInitViews.GetValueOnRenderThread() > 0.0f)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_InitViews_Intentional_Stall);
2015-08-03 11:44:45 -04:00
FPlatformProcess::Sleep(CVarStallInitViews.GetValueOnRenderThread() / 1000.0f);
}
#endif
if (GRHICommandList.UseParallelAlgorithms())
{
// there are dynamic attempts to get this target during parallel rendering
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
Views[ViewIndex].GetEyeAdaptation(RHICmdList);
}
}
2015-05-18 13:21:23 -04:00
if (ShouldPrepareDistanceFields())
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_DistanceFieldAO_Init);
GDistanceFieldVolumeTextureAtlas.UpdateAllocations();
UpdateGlobalDistanceFieldObjectBuffers(RHICmdList);
2015-02-06 23:31:19 -05:00
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
Views[ViewIndex].HeightfieldLightingViewInfo.SetupVisibleHeightfields(Views[ViewIndex], RHICmdList);
if (UseGlobalDistanceField())
{
// Use the skylight's max distance if there is one
const float OcclusionMaxDistance = Scene->SkyLight && !Scene->SkyLight->bWantsStaticShadowing ? Scene->SkyLight->OcclusionMaxDistance : Scene->DefaultMaxDistanceFieldOcclusionDistance;
UpdateGlobalDistanceFieldVolume(RHICmdList, Views[ViewIndex], Scene, OcclusionMaxDistance, Views[ViewIndex].GlobalDistanceFieldInfo);
}
2015-02-06 23:31:19 -05:00
}
}
if (GRHIThread)
{
// we will probably stall on occlusion queries, so might as well have the RHI thread and GPU work while we wait.
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_PostInitViews_FlushDel);
FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources);
}
const bool bIsWireframe = ViewFamily.EngineShowFlags.Wireframe;
static const auto ClearMethodCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ClearSceneMethod"));
bool bRequiresRHIClear = true;
bool bRequiresFarZQuadClear = false;
const bool bUseGBuffer = !IsAnyForwardShadingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel));
if (ClearMethodCVar)
{
int32 clearMethod = ClearMethodCVar->GetValueOnRenderThread();
if (clearMethod == 0 && !ViewFamily.EngineShowFlags.Game)
{
// Do not clear the scene only if the view family is in game mode.
clearMethod = 1;
}
switch (clearMethod)
{
case 0: // No clear
{
bRequiresRHIClear = false;
bRequiresFarZQuadClear = false;
break;
}
case 1: // RHICmdList.Clear
{
bRequiresRHIClear = true;
bRequiresFarZQuadClear = false;
break;
}
case 2: // Clear using far-z quad
{
bRequiresFarZQuadClear = true;
bRequiresRHIClear = false;
break;
}
}
}
// Always perform a full buffer clear for wireframe, shader complexity view mode, and stationary light overlap viewmode.
if (bIsWireframe || ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.StationaryLightOverlap)
{
bRequiresRHIClear = true;
}
// force using occ queries for wireframe if rendering is parented or frozen in the first view
check(Views.Num());
#if (UE_BUILD_SHIPPING || UE_BUILD_TEST)
const bool bIsViewFrozen = false;
const bool bHasViewParent = false;
#else
const bool bIsViewFrozen = Views[0].State && ((FSceneViewState*)Views[0].State)->bIsFrozen;
const bool bHasViewParent = Views[0].State && ((FSceneViewState*)Views[0].State)->HasViewParent();
#endif
2014-08-19 10:41:34 -04:00
const bool bIsOcclusionTesting = DoOcclusionQueries(FeatureLevel) && (!bIsWireframe || bIsViewFrozen || bHasViewParent);
// Dynamic vertex and index buffers need to be committed before rendering.
if (!bDoInitViewAftersPrepass)
{
{
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FGlobalDynamicVertexBuffer_Commit);
FGlobalDynamicVertexBuffer::Get().Commit();
FGlobalDynamicIndexBuffer::Get().Commit();
}
}
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_MotionBlurStartFrame);
Scene->MotionBlurInfoData.StartFrame(ViewFamily.bWorldIsPaused);
}
// Notify the FX system that the scene is about to be rendered.
bool bLateFXPrerender = CVarFXSystemPreRenderAfterPrepass.GetValueOnRenderThread() > 0;
bool bDoFXPrerender = Scene->FXSystem && Views.IsValidIndex(0);
if (!bLateFXPrerender && bDoFXPrerender)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FXSystem_PreRender);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_FXPreRender));
2015-05-18 13:21:23 -04:00
Scene->FXSystem->PreRender(RHICmdList, &Views[0].GlobalDistanceFieldInfo.ParameterData);
}
if (GEnableGPUSkinCache)
{
GGPUSkinCache.TransitionToReadable(RHICmdList);
}
bool bDidAfterTaskWork = false;
auto AfterTasksAreStarted = [&bDidAfterTaskWork, bDoInitViewAftersPrepass, this, &RHICmdList, &ILCTaskData, &SortEvents, bLateFXPrerender, bDoFXPrerender]()
{
if (!bDidAfterTaskWork)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_AfterPrepassTasksWork);
bDidAfterTaskWork = true; // only do this once
if (bDoInitViewAftersPrepass)
{
InitViewsPossiblyAfterPrepass(RHICmdList, ILCTaskData, SortEvents);
{
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FGlobalDynamicVertexBuffer_Commit);
FGlobalDynamicVertexBuffer::Get().Commit();
FGlobalDynamicIndexBuffer::Get().Commit();
}
ServiceLocalQueue();
}
if (bLateFXPrerender && bDoFXPrerender)
{
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FXSystem_PreRender);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_FXPreRender));
Scene->FXSystem->PreRender(RHICmdList, &Views[0].GlobalDistanceFieldInfo.ParameterData);
ServiceLocalQueue();
}
}
};
// Draw the scene pre-pass / early z pass, populating the scene depth buffer and HiZ
GRenderTargetPool.AddPhaseEvent(TEXT("EarlyZPass"));
const bool bNeedsPrePass = NeedsPrePass(this);
bool bDepthWasCleared;
if (bNeedsPrePass)
{
bDepthWasCleared = RenderPrePass(RHICmdList, AfterTasksAreStarted);
}
else
{
// we didn't do the prepass, but we still want the HMD mask if there is one
AfterTasksAreStarted();
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_PrePass));
bDepthWasCleared = RenderPrePassHMD(RHICmdList);
}
check(bDidAfterTaskWork);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterPrePass));
ServiceLocalQueue();
const bool bShouldRenderVelocities = ShouldRenderVelocities();
const bool bUseVelocityGBuffer = FVelocityRendering::OutputsToGBuffer();
const bool bUseSelectiveBasePassOutputs = UseSelectiveBasePassOutputs();
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_AllocGBufferTargets);
SceneContext.PreallocGBufferTargets(bUseVelocityGBuffer); // Even if !bShouldRenderVelocities, the velocity buffer must be bound because it's a compile time option for the shader.
SceneContext.AllocGBufferTargets(RHICmdList);
}
//occlusion can't run before basepass if there's no prepass to fill in some depth to occlude against.
bool bOcclusionBeforeBasePass = ((CVarOcclusionQueryLocation.GetValueOnRenderThread() == 1) && bNeedsPrePass) || IsForwardShadingEnabled(FeatureLevel);
bool bHZBBeforeBasePass = bOcclusionBeforeBasePass && (EarlyZPassMode == EDepthDrawingMode::DDM_AllOccluders);
RenderOcclusion(RHICmdList, bOcclusionBeforeBasePass, bHZBBeforeBasePass);
ServiceLocalQueue();
if (bOcclusionBeforeBasePass)
{
RenderShadowDepthMaps(RHICmdList);
ServiceLocalQueue();
}
// Clear LPVs for all views
if (FeatureLevel >= ERHIFeatureLevel::SM5)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_ClearLPVs);
ClearLPVs(RHICmdList);
ServiceLocalQueue();
}
if(GetCustomDepthPassLocation() == 0)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_CustomDepthPass0);
RenderCustomDepthPassAtLocation(RHICmdList, 0);
}
ComputeLightGrid(RHICmdList);
if (IsForwardShadingEnabled(FeatureLevel))
{
RenderForwardShadingShadowProjections(RHICmdList);
RenderIndirectCapsuleShadows(
RHICmdList,
NULL,
NULL);
}
// only temporarily available after early z pass and until base pass
check(!SceneContext.DBufferA);
check(!SceneContext.DBufferB);
check(!SceneContext.DBufferC);
if (bDBuffer)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_DBuffer);
SceneContext.ResolveSceneDepthTexture(RHICmdList);
SceneContext.ResolveSceneDepthToAuxiliaryTexture(RHICmdList);
2015-04-23 13:22:07 -04:00
// e.g. DBuffer deferred decals
for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView,Views.Num() > 1, TEXT("View%d"), ViewIndex);
2015-04-23 13:22:07 -04:00
GCompositionLighting.ProcessBeforeBasePass(RHICmdList, Views[ViewIndex]);
}
2015-10-10 17:47:14 -04:00
//GBuffer pass will want to write to SceneDepthZ
RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, SceneContext.GetSceneDepthTexture());
ServiceLocalQueue();
}
2014-10-27 20:23:51 -04:00
// Clear the G Buffer render targets
bool bIsGBufferCurrent = false;
if (bRequiresRHIClear)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_SetAndClearViewGBuffer);
2014-10-27 20:23:51 -04:00
// set GBuffer to be current, and clear it
SetAndClearViewGBuffer(RHICmdList, Views[0], !bDepthWasCleared);
// depth was cleared now no matter what
bDepthWasCleared = true;
bIsGBufferCurrent = true;
ServiceLocalQueue();
2014-10-27 20:23:51 -04:00
}
if (bIsWireframe && FSceneRenderer::ShouldCompositeEditorPrimitives(Views[0]))
{
// In Editor we want wire frame view modes to be MSAA for better quality. Resolve will be done with EditorPrimitives
SetRenderTarget(RHICmdList, SceneContext.GetEditorPrimitivesColor(RHICmdList), SceneContext.GetEditorPrimitivesDepth(RHICmdList), ESimpleRenderTargetMode::EClearColorAndDepth);
}
2014-10-27 20:23:51 -04:00
else if (!bIsGBufferCurrent)
{
2014-10-27 20:23:51 -04:00
// make sure the GBuffer is set, in case we didn't need to clear above
ERenderTargetLoadAction DepthLoadAction = bDepthWasCleared ? ERenderTargetLoadAction::ELoad : ERenderTargetLoadAction::EClear;
SceneContext.BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::ENoAction, DepthLoadAction, ViewFamily.EngineShowFlags.ShaderComplexity);
}
if (GbEnableAsyncComputeTranslucencyLightingVolumeClear && GSupportsEfficientAsyncCompute)
{
ClearTranslucentVolumeLightingAsyncCompute(RHICmdList);
}
2014-04-23 19:52:11 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("BasePass"));
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_BasePass));
RenderBasePass(RHICmdList);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterBasePass));
ServiceLocalQueue();
if (ViewFamily.EngineShowFlags.VisualizeLightCulling)
{
// clear out emissive and baked lighting (not too efficient but simple and only needed for this debug view)
SceneContext.BeginRenderingSceneColor(RHICmdList);
RHICmdList.Clear(true, FLinearColor(0, 0, 0, 0), false, (float)ERHIZBuffer::FarPlane, false, 0, FIntRect());
}
SceneContext.DBufferA.SafeRelease();
SceneContext.DBufferB.SafeRelease();
SceneContext.DBufferC.SafeRelease();
// only temporarily available after early z pass and until base pass
check(!SceneContext.DBufferA);
check(!SceneContext.DBufferB);
check(!SceneContext.DBufferC);
if (bRequiresFarZQuadClear)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_ClearGBufferAtMaxZ);
// Clears view by drawing quad at maximum Z
// TODO: if all the platforms have fast color clears, we can replace this with an RHICmdList.Clear.
ClearGBufferAtMaxZ(RHICmdList);
ServiceLocalQueue();
bRequiresFarZQuadClear = false;
}
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_ResolveDepth_After_Basepass);
SceneContext.ResolveSceneDepthTexture(RHICmdList);
SceneContext.ResolveSceneDepthToAuxiliaryTexture(RHICmdList);
}
bool bOcclusionAfterBasePass = bIsOcclusionTesting && !bOcclusionBeforeBasePass;
bool bHZBAfterBasePass = !bHZBBeforeBasePass;
RenderOcclusion(RHICmdList, bOcclusionAfterBasePass, bHZBAfterBasePass);
ServiceLocalQueue();
if (!bOcclusionBeforeBasePass)
{
RenderShadowDepthMaps(RHICmdList);
ServiceLocalQueue();
}
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Resolve_After_Basepass);
SceneContext.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY));
SceneContext.FinishRenderingGBuffer(RHICmdList);
}
if(GetCustomDepthPassLocation() == 1)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_CustomDepthPass1);
RenderCustomDepthPassAtLocation(RHICmdList, 1);
}
ServiceLocalQueue();
// Notify the FX system that opaque primitives have been rendered and we now have a valid depth buffer.
if (Scene->FXSystem && Views.IsValidIndex(0))
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FXSystem_PostRenderOpaque);
Scene->FXSystem->PostRenderOpaque(
RHICmdList,
Views.GetData(),
SceneContext.GetSceneDepthTexture(),
SceneContext.GetGBufferATexture()
);
ServiceLocalQueue();
}
TRefCountPtr<IPooledRenderTarget> VelocityRT;
if (bUseVelocityGBuffer)
{
VelocityRT = SceneContext.GetGBufferVelocityRT();
}
if (bShouldRenderVelocities && (!bUseVelocityGBuffer || bUseSelectiveBasePassOutputs))
{
// Render the velocities of movable objects
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_Velocity));
RenderVelocities(RHICmdList, VelocityRT);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterVelocity));
ServiceLocalQueue();
}
// Copy lighting channels out of stencil before deferred decals which overwrite those values
CopyStencilToLightingChannelTexture(RHICmdList);
{
GCompositionLighting.GfxWaitForAsyncSSAO(RHICmdList);
}
2015-04-13 15:39:50 -04:00
// Pre-lighting composition lighting stage
// e.g. deferred decals, SSAO
if (FeatureLevel >= ERHIFeatureLevel::SM4)
2015-04-13 15:39:50 -04:00
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_AfterBasePass);
2015-04-13 15:39:50 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("AfterBasePass"));
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
GCompositionLighting.ProcessAfterBasePass(RHICmdList, Views[ViewIndex]);
}
ServiceLocalQueue();
2015-04-13 15:39:50 -04:00
}
{
SCOPED_DRAW_EVENT(RHICmdList, ClearStencilFromBasePass);
FRHISetRenderTargetsInfo Info(0, NULL, FRHIDepthRenderTargetView(
SceneContext.GetSceneDepthSurface(),
ERenderTargetLoadAction::ENoAction,
ERenderTargetStoreAction::ENoAction,
ERenderTargetLoadAction::EClear,
ERenderTargetStoreAction::EStore,
FExclusiveDepthStencil::DepthNop_StencilWrite));
// Clear stencil to 0 now that deferred decals are done using what was setup in the base pass
// Shadow passes and other users of stencil assume it is cleared to 0 going in
RHICmdList.SetRenderTargetsAndClear(Info);
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, SceneContext.GetSceneDepthSurface());
}
// Render lighting.
if (ViewFamily.EngineShowFlags.Lighting
&& FeatureLevel >= ERHIFeatureLevel::SM4
&& ViewFamily.EngineShowFlags.DeferredLighting
&& bUseGBuffer)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Lighting);
2014-04-23 19:52:11 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("Lighting"));
// These modulate the scenecolor output from the basepass, which is assumed to be indirect lighting
RenderIndirectCapsuleShadows(
RHICmdList,
SceneContext.GetSceneColorSurface(),
SceneContext.bScreenSpaceAOIsValid ? SceneContext.ScreenSpaceAO->GetRenderTargetItem().TargetableTexture : NULL);
TRefCountPtr<IPooledRenderTarget> DynamicBentNormalAO;
// These modulate the scenecolor output from the basepass, which is assumed to be indirect lighting
RenderDFAOAsIndirectShadowing(RHICmdList, VelocityRT, DynamicBentNormalAO);
// Clear the translucent lighting volumes before we accumulate
if ((GbEnableAsyncComputeTranslucencyLightingVolumeClear && GSupportsEfficientAsyncCompute) == false)
{
ClearTranslucentVolumeLighting(RHICmdList);
}
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_Lighting));
RenderLights(RHICmdList);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterLighting));
ServiceLocalQueue();
2014-06-30 16:04:34 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("AfterRenderLights"));
InjectAmbientCubemapTranslucentVolumeLighting(RHICmdList);
ServiceLocalQueue();
// Filter the translucency lighting volume now that it is complete
FilterTranslucentVolumeLighting(RHICmdList);
ServiceLocalQueue();
// Pre-lighting composition lighting stage
// e.g. LPV indirect
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
FViewInfo& View = Views[ViewIndex];
if(IsLpvIndirectPassRequired(View))
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView,Views.Num() > 1, TEXT("View%d"), ViewIndex);
GCompositionLighting.ProcessLpvIndirect(RHICmdList, View);
ServiceLocalQueue();
}
}
RenderDynamicSkyLighting(RHICmdList, VelocityRT, DynamicBentNormalAO);
ServiceLocalQueue();
2014-08-28 13:54:31 -04:00
// SSS need the SceneColor finalized as an SRV.
SceneContext.FinishRenderingSceneColor(RHICmdList, true);
// Render reflections that only operate on opaque pixels
2014-08-28 13:54:31 -04:00
RenderDeferredReflections(RHICmdList, DynamicBentNormalAO);
ServiceLocalQueue();
// Post-lighting composition lighting stage
// e.g. ScreenSpaceSubsurfaceScattering
for(int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView,Views.Num() > 1, TEXT("View%d"), ViewIndex);
GCompositionLighting.ProcessAfterLighting(RHICmdList, Views[ViewIndex]);
}
ServiceLocalQueue();
}
if (ViewFamily.EngineShowFlags.StationaryLightOverlap &&
FeatureLevel >= ERHIFeatureLevel::SM4)
{
RenderStationaryLightOverlap(RHICmdList);
ServiceLocalQueue();
}
FLightShaftsOutput LightShaftOutput;
// Draw Lightshafts
if (ViewFamily.EngineShowFlags.LightShafts)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderLightShaftOcclusion);
RenderLightShaftOcclusion(RHICmdList, LightShaftOutput);
ServiceLocalQueue();
}
// Draw atmosphere
if (ShouldRenderAtmosphere(ViewFamily))
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderAtmosphere);
if (Scene->AtmosphericFog)
{
// Update RenderFlag based on LightShaftTexture is valid or not
if (LightShaftOutput.LightShaftOcclusion)
{
Scene->AtmosphericFog->RenderFlag &= EAtmosphereRenderFlag::E_LightShaftMask;
}
else
{
Scene->AtmosphericFog->RenderFlag |= EAtmosphereRenderFlag::E_DisableLightShaft;
}
#if WITH_EDITOR
if (Scene->bIsEditorScene)
{
// Precompute Atmospheric Textures
Scene->AtmosphericFog->PrecomputeTextures(RHICmdList, Views.GetData(), &ViewFamily);
}
#endif
RenderAtmosphere(RHICmdList, LightShaftOutput);
ServiceLocalQueue();
}
}
2014-04-23 19:52:11 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("Fog"));
// Draw fog.
if (ShouldRenderFog(ViewFamily))
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderFog);
RenderFog(RHICmdList, LightShaftOutput);
ServiceLocalQueue();
}
if (GetRendererModule().HasPostOpaqueExtentions())
{
SceneContext.BeginRenderingSceneColor(RHICmdList);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
GetRendererModule().RenderPostOpaqueExtensions(View, RHICmdList, SceneContext);
}
2015-10-31 14:47:30 -04:00
SceneContext.FinishRenderingSceneColor(RHICmdList, true);
}
// No longer needed, release
LightShaftOutput.LightShaftOcclusion = NULL;
2014-04-23 19:52:11 -04:00
GRenderTargetPool.AddPhaseEvent(TEXT("Translucency"));
// Draw translucency.
if (ViewFamily.EngineShowFlags.Translucency)
{
SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_Translucency));
RenderTranslucency(RHICmdList);
ServiceLocalQueue();
2014-06-24 20:14:10 -04:00
if(GetRefractionQuality(ViewFamily) > 0)
{
2014-06-24 20:14:10 -04:00
// To apply refraction effect by distorting the scene color.
// After non separate translucency as that is considered at scene depth anyway
// It allows skybox translucency (set to non separate translucency) to be refracted.
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_RenderDistortion));
RenderDistortion(RHICmdList);
ServiceLocalQueue();
}
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterTranslucency));
}
if (ViewFamily.EngineShowFlags.LightShafts)
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderLightShaftBloom);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_LightShaftBloom));
RenderLightShaftBloom(RHICmdList);
ServiceLocalQueue();
}
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex)
{
const FViewInfo& View = Views[ViewIndex];
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
GetRendererModule().RenderOverlayExtensions(View, RHICmdList, SceneContext);
}
if (ViewFamily.EngineShowFlags.VisualizeDistanceFieldAO || ViewFamily.EngineShowFlags.VisualizeDistanceFieldGI)
2014-06-03 15:53:13 -04:00
{
// Use the skylight's max distance if there is one, to be consistent with DFAO shadowing on the skylight
const float OcclusionMaxDistance = Scene->SkyLight && !Scene->SkyLight->bWantsStaticShadowing ? Scene->SkyLight->OcclusionMaxDistance : Scene->DefaultMaxDistanceFieldOcclusionDistance;
2014-08-28 13:54:31 -04:00
TRefCountPtr<IPooledRenderTarget> DummyOutput;
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_RenderDistanceFieldLighting));
RenderDistanceFieldLighting(RHICmdList, FDistanceFieldAOParameters(OcclusionMaxDistance), VelocityRT, DummyOutput, DummyOutput, false, ViewFamily.EngineShowFlags.VisualizeDistanceFieldAO, ViewFamily.EngineShowFlags.VisualizeDistanceFieldGI);
ServiceLocalQueue();
2014-08-28 13:54:31 -04:00
}
if (ViewFamily.EngineShowFlags.VisualizeMeshDistanceFields)
{
RenderMeshDistanceFieldVisualization(RHICmdList, FDistanceFieldAOParameters(Scene->DefaultMaxDistanceFieldOcclusionDistance));
ServiceLocalQueue();
2014-06-03 15:53:13 -04:00
}
// Resolve the scene color for post processing.
SceneContext.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY));
CopySceneCaptureComponentToTarget(RHICmdList);
// Finish rendering for each view.
if (ViewFamily.bResolveScene)
{
SCOPED_DRAW_EVENT(RHICmdList, PostProcessing);
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Postprocessing);
SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime);
2014-09-02 16:37:25 -04:00
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_PostProcessing));
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
2014-09-02 16:37:25 -04:00
{
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
2014-09-02 16:37:25 -04:00
GPostProcessing.Process(RHICmdList, Views[ ViewIndex ], VelocityRT);
}
// End of frame, we don't need it anymore
FSceneRenderTargets::Get(RHICmdList).FreeSeparateTranslucencyDepth();
// we rendered to it during the frame, seems we haven't made use of it, because it should be released
check(!FSceneRenderTargets::Get(RHICmdList).SeparateTranslucencyRT);
}
else
{
// Release the original reference on the scene render targets
SceneContext.AdjustGBufferRefCount(RHICmdList, -1);
}
2014-12-18 17:17:28 -05:00
//grab the new transform out of the proxies for next frame
if (VelocityRT)
2014-12-18 17:17:28 -05:00
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_UpdateMotionBlurCache);
2014-12-18 17:17:28 -05:00
Scene->MotionBlurInfoData.UpdateMotionBlurCache(Scene);
}
2014-09-02 16:37:25 -04:00
VelocityRT.SafeRelease();
{
2015-12-02 16:42:06 -05:00
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderFinish);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_RenderFinish));
RenderFinish(RHICmdList);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterFrame));
}
ServiceLocalQueue();
}
/** A simple pixel shader used on PC to read scene depth from scene color alpha and write it to a downsized depth buffer. */
class FDownsampleSceneDepthPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FDownsampleSceneDepthPS,Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
2014-08-25 14:41:54 -04:00
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
FDownsampleSceneDepthPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FGlobalShader(Initializer)
{
SceneTextureParameters.Bind(Initializer.ParameterMap);
ProjectionScaleBias.Bind(Initializer.ParameterMap,TEXT("ProjectionScaleBias"));
SourceTexelOffsets01.Bind(Initializer.ParameterMap,TEXT("SourceTexelOffsets01"));
SourceTexelOffsets23.Bind(Initializer.ParameterMap,TEXT("SourceTexelOffsets23"));
UseMaxDepth.Bind(Initializer.ParameterMap, TEXT("UseMaxDepth"));
}
FDownsampleSceneDepthPS() {}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, bool bUseMaxDepth)
{
FGlobalShader::SetParameters(RHICmdList, GetPixelShader(), View);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
// Used to remap view space Z (which is stored in scene color alpha) into post projection z and w so we can write z/w into the downsized depth buffer
const FVector2D ProjectionScaleBiasValue(View.ViewMatrices.ProjMatrix.M[2][2], View.ViewMatrices.ProjMatrix.M[3][2]);
SetShaderValue(RHICmdList, GetPixelShader(), ProjectionScaleBias, ProjectionScaleBiasValue);
SetShaderValue(RHICmdList, GetPixelShader(), UseMaxDepth, (bUseMaxDepth ? 1.0f : 0.0f));
FIntPoint BufferSize = SceneContext.GetBufferSizeXY();
const uint32 DownsampledBufferSizeX = BufferSize.X / SceneContext.GetSmallColorDepthDownsampleFactor();
const uint32 DownsampledBufferSizeY = BufferSize.Y / SceneContext.GetSmallColorDepthDownsampleFactor();
// Offsets of the four full resolution pixels corresponding with a low resolution pixel
const FVector4 Offsets01(0.0f, 0.0f, 1.0f / DownsampledBufferSizeX, 0.0f);
SetShaderValue(RHICmdList, GetPixelShader(), SourceTexelOffsets01, Offsets01);
const FVector4 Offsets23(0.0f, 1.0f / DownsampledBufferSizeY, 1.0f / DownsampledBufferSizeX, 1.0f / DownsampledBufferSizeY);
SetShaderValue(RHICmdList, GetPixelShader(), SourceTexelOffsets23, Offsets23);
SceneTextureParameters.Set(RHICmdList, GetPixelShader(), View);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << ProjectionScaleBias;
Ar << SourceTexelOffsets01;
Ar << SourceTexelOffsets23;
Ar << SceneTextureParameters;
Ar << UseMaxDepth;
return bShaderHasOutdatedParameters;
}
FShaderParameter ProjectionScaleBias;
FShaderParameter SourceTexelOffsets01;
FShaderParameter SourceTexelOffsets23;
FSceneTextureShaderParameters SceneTextureParameters;
FShaderParameter UseMaxDepth;
};
IMPLEMENT_SHADER_TYPE(,FDownsampleSceneDepthPS,TEXT("DownsampleDepthPixelShader"),TEXT("Main"),SF_Pixel);
FGlobalBoundShaderState DownsampleDepthBoundShaderState;
/** Updates the downsized depth buffer with the current full resolution depth buffer. */
void FDeferredShadingSceneRenderer::UpdateDownsampledDepthSurface(FRHICommandList& RHICmdList)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
if (SceneContext.UseDownsizedOcclusionQueries() && (FeatureLevel >= ERHIFeatureLevel::SM4))
{
RHICmdList.TransitionResource( EResourceTransitionAccess::EReadable, SceneContext.GetSceneDepthSurface() );
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
DownsampleDepthSurface(RHICmdList, SceneContext.GetSmallDepthSurface(), View, 1.0f / SceneContext.GetSmallColorDepthDownsampleFactor(), true);
}
}
}
/** Downsample the scene depth with a specified scale factor to a specified render target
*/
void FDeferredShadingSceneRenderer::DownsampleDepthSurface(FRHICommandList& RHICmdList, const FTexture2DRHIRef& RenderTarget, const FViewInfo& View, float ScaleFactor, bool bUseMaxDepth)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SetRenderTarget(RHICmdList, NULL, RenderTarget);
SCOPED_DRAW_EVENT(RHICmdList, DownsampleDepth);
// Set shaders and texture
TShaderMapRef<FScreenVS> ScreenVertexShader(View.ShaderMap);
TShaderMapRef<FDownsampleSceneDepthPS> PixelShader(View.ShaderMap);
extern TGlobalResource<FFilterVertexDeclaration> GFilterVertexDeclaration;
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, DownsampleDepthBoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *ScreenVertexShader, *PixelShader);
RHICmdList.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI());
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true, CF_Always>::GetRHI());
PixelShader->SetParameters(RHICmdList, View, bUseMaxDepth);
const uint32 DownsampledX = FMath::TruncToInt(View.ViewRect.Min.X * ScaleFactor);
const uint32 DownsampledY = FMath::TruncToInt(View.ViewRect.Min.Y * ScaleFactor);
const uint32 DownsampledSizeX = FMath::TruncToInt(View.ViewRect.Width() * ScaleFactor);
const uint32 DownsampledSizeY = FMath::TruncToInt(View.ViewRect.Height() * ScaleFactor);
RHICmdList.SetViewport(DownsampledX, DownsampledY, 0.0f, DownsampledX + DownsampledSizeX, DownsampledY + DownsampledSizeY, 1.0f);
DrawRectangle(
RHICmdList,
0, 0,
DownsampledSizeX, DownsampledSizeY,
View.ViewRect.Min.X, View.ViewRect.Min.Y,
View.ViewRect.Width(), View.ViewRect.Height(),
FIntPoint(DownsampledSizeX, DownsampledSizeY),
SceneContext.GetBufferSizeXY(),
*ScreenVertexShader,
EDRF_UseTriangleOptimization);
2015-10-31 14:47:30 -04:00
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget);
}
/** */
class FCopyStencilToLightingChannelsPS : public FGlobalShader
{
DECLARE_SHADER_TYPE(FCopyStencilToLightingChannelsPS,Global);
public:
static bool ShouldCache(EShaderPlatform Platform)
{
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
}
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
OutEnvironment.SetDefine(TEXT("STENCIL_LIGHTING_CHANNELS_SHIFT"), STENCIL_LIGHTING_CHANNELS_BIT_ID);
OutEnvironment.SetRenderTargetOutputFormat(0, PF_R16_UINT);
}
FCopyStencilToLightingChannelsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
FGlobalShader(Initializer)
{
SceneStencilTexture.Bind(Initializer.ParameterMap,TEXT("SceneStencilTexture"));
}
FCopyStencilToLightingChannelsPS() {}
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
{
FGlobalShader::SetParameters(RHICmdList, GetPixelShader(), View);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SetSRVParameter(RHICmdList, GetPixelShader(), SceneStencilTexture, SceneContext.SceneStencilSRV);
}
virtual bool Serialize(FArchive& Ar) override
{
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
Ar << SceneStencilTexture;
return bShaderHasOutdatedParameters;
}
FShaderResourceParameter SceneStencilTexture;
};
IMPLEMENT_SHADER_TYPE(,FCopyStencilToLightingChannelsPS,TEXT("DownsampleDepthPixelShader"),TEXT("CopyStencilToLightingChannelsPS"),SF_Pixel);
FGlobalBoundShaderState CopyStencilBoundShaderState;
void FDeferredShadingSceneRenderer::CopyStencilToLightingChannelTexture(FRHICommandList& RHICmdList)
{
bool bAnyViewUsesLightingChannels = false;
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
bAnyViewUsesLightingChannels = bAnyViewUsesLightingChannels || View.bUsesLightingChannels;
}
if (bAnyViewUsesLightingChannels)
{
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
SCOPED_DRAW_EVENT(RHICmdList, CopyStencilToLightingChannels);
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, SceneContext.GetSceneDepthTexture());
SceneContext.AllocateLightingChannelTexture(RHICmdList);
// Set the light attenuation surface as the render target, and the scene depth buffer as the depth-stencil surface.
SetRenderTarget(RHICmdList, SceneContext.LightingChannels->GetRenderTargetItem().TargetableTexture, nullptr, ESimpleRenderTargetMode::EExistingColorAndDepth, FExclusiveDepthStencil::DepthNop_StencilNop, true);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
// Set shaders and texture
TShaderMapRef<FScreenVS> ScreenVertexShader(View.ShaderMap);
TShaderMapRef<FCopyStencilToLightingChannelsPS> PixelShader(View.ShaderMap);
extern TGlobalResource<FFilterVertexDeclaration> GFilterVertexDeclaration;
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, CopyStencilBoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *ScreenVertexShader, *PixelShader);
RHICmdList.SetBlendState(TStaticBlendState<CW_RGBA>::GetRHI());
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
PixelShader->SetParameters(RHICmdList, View);
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Min.X + View.ViewRect.Width(), View.ViewRect.Min.Y + View.ViewRect.Height(), 1.0f);
DrawRectangle(
RHICmdList,
0, 0,
View.ViewRect.Width(), View.ViewRect.Height(),
View.ViewRect.Min.X, View.ViewRect.Min.Y,
View.ViewRect.Width(), View.ViewRect.Height(),
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
SceneContext.GetBufferSizeXY(),
*ScreenVertexShader,
EDRF_UseTriangleOptimization);
}
FResolveParams ResolveParams;
RHICmdList.CopyToResolveTarget(
SceneContext.LightingChannels->GetRenderTargetItem().TargetableTexture,
SceneContext.LightingChannels->GetRenderTargetItem().TargetableTexture,
true,
ResolveParams);
}
}