You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3045482 on 2016/07/11 by Zabir.Hoque DX12 Quries need to individually track their syncpoints. Only when resolving a query on the same frame should be stall. Change 3045929 on 2016/07/12 by Simon.Tovey Removing some deprecated node types from Niagara Change 3045951 on 2016/07/12 by Ben.Woodhouse D3D11 Log detailed live device info on shutdown if the debug layer is enabled (including resource types) Change3046019on 2016/07/12 by Chris.Bunner Fixed typo in material input name. #jira UE-5575 Change 3046053 on 2016/07/12 by Rolando.Caloca DR - Fix GL4 shutdown #jira UE-32799 Change 3046055 on 2016/07/12 by Rolando.Caloca DR - vk - Fix NumInstances=0 Change 3046063 on 2016/07/12 by Rolando.Caloca DR - vk - Added flat to uint layouts per glslang - Fix bad extension on dumped shaders Change 3046067 on 2016/07/12 by Rolando.Caloca DR - vk - Fix check when not using color RT - Added queue submit & present counters Change3046088on 2016/07/12 by Ben.Woodhouse Live GPU stats A non-hierarchical realtime high level GPU profiler with support for cumulative stat recording. Stats are added with SCOPED_GPU_STAT macros, e.g. SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Distortion) The bulk of the files in this change are simply instrumentation for the renderer. The core changes are in SceneUtils.cpp/h and D3D11Query.cpp (this is the XB1/DX11X implementation of timestamp RHI queries, which was missing) Note: this is currently disabled by default. Enable with the cvar r.gpustatsenabled Tested on PC, XB1, PS4 Change 3046128 on 2016/07/12 by Olaf.Piesche Max draw distance and fade range for lights, requested by JonL Change 3046183 on 2016/07/12 by Ben.Woodhouse PR #2532: Fix SSAO being applied in unlit viewmode (Contributed by nick-penwarden) Change 3046223 on 2016/07/12 by Luke.Thatcher Fix Scene Cube Captures. SceneCaptureSource flag on the ViewFamily was not set for cube components. #jira UE-32345 Change 3046228 on 2016/07/12 by Marc.Olano Add Voronoi noise to Noise material node. Four versions with differing speed/quality levels accessed through the Quality value in the material node. Tooltips give estimates of the cost of each. Also includes spiffy new Rand3DPCG16 and Rand3DPCG32 int3 to int3 hash functions, and a 20% improvement on the computed gradient noise. Change 3046269 on 2016/07/12 by Rolando.Caloca DR - Skip flush on RHIDiscardRenderTargets and only use it on platforms that need it (ie OpenGL) Change 3046294 on 2016/07/12 by Rolando.Caloca DR - Fix static analyisis warning C6326: Potential comparison of a constant with another constant. Change 3046295 on 2016/07/12 by Rolando.Caloca DR - Fix the previous fix Change 3046731 on 2016/07/12 by Marc.Olano Fix typo in shader random number constant: repeated extra digit made it too big. Change 3046796 on 2016/07/12 by Uriel.Doyon The texture streaming manager now keeps a set of all valid textures. This is used to prevent from indirecting deleted memory upon SetTexturesRemovedTimestamp. #jira UE-33048 Change 3046800 on 2016/07/12 by Rolando.Caloca DR - vk - Added create image & renderpass dump Change 3046845 on 2016/07/12 by John.Billon Forgot to apply MaxGPUSkinBones Cvar access changes in a few locations. Change 3047023 on 2016/07/12 by Olaf.Piesche Niagara: -a bit of cleanup -now store and double buffer attributes individually, eliminating unnecessary copy of unused attributes -removed FNiagaraConstantMap, replaced with an instance of FNiagaraConstants -some code simplification -removed some deprecated structs and code used only by old content Change 3047052 on 2016/07/12 by Zabir.Hoque Unshelved from pending changelist '3044062': PR #2588: Adding blend mode BLEND_AlphaComposite (4.12) (Contributed by moritz-wundke) Change 3047727 on 2016/07/13 by Luke.Thatcher Fix Scene Capture Components only updating every other frame. #jira UE-32581 Change 3047919 on 2016/07/13 by Olaf.Piesche CMask decode, use in deferred decals, for PS4 Change 3047921 on 2016/07/13 by Uriel.Doyon "Build Texture Streaming" will now remove duplicate error msg when computing texcoord scales. Also, several texture messages are packed on the same line if they relate to the same material. Change 3047952 on 2016/07/13 by Rolando.Caloca DR - vk - Initial prep pass for separating combined images & samplers Change 3048648 on 2016/07/13 by Marcus.Wassmer Fix rare GPU hang when asynctexture reallocs would overlap with EndFrame Change 3049058 on 2016/07/13 by Rolando.Caloca DR - vk - timestamps Change 3049725 on 2016/07/14 by Marcus.Wassmer Fix autosdk bug where not having a platform directory sync'd at all would break manual SDK detection Change 3049742 on 2016/07/14 by Rolando.Caloca DR - Fix warning Change 3049902 on 2016/07/14 by Rolando.Caloca DR - Fix typo Change 3050345 on 2016/07/14 by Olaf.Piesche UE-23925 Clamping noise tessellation for beams at a high but sensible value; also making sure during beam index buffer building that we never get over 2^16 indices; this is a bit hokey, but there are so many variables that can influence triangle/index count, that this is the only way to be sure (short of nuking the entire site from orbit). Change 3050409 on 2016/07/14 by Olaf.Piesche Replicating 3049049; missing break and check for active particles when resolving a source point to avoid a potential crash Change 3050809 on 2016/07/14 by Rolando.Caloca DR - vk - Remove redundant validation layers Change 3051319 on 2016/07/15 by Ben.Woodhouse Fix for world space camera position not being exposed in decal pixel shaders; also fixes decal lighting missing spec and reflection The fix was to calculate ResolvedView at the top of the shader. Previously this was not initialized #jira UE-31976 Change 3051692 on 2016/07/15 by Rolando.Caloca DR - vk - Enable RHI thread by default Change 3052103 on 2016/07/15 by Uriel.Doyon Disabled depth offset in depth only pixel shaders when using debug view shaders (to prevent Z fighting). #jira UE-32765 Change 3052140 on 2016/07/15 by Rolando.Caloca DR - vk - Fix shader snafu Change 3052495 on 2016/07/15 by Rolando.Caloca DR - Fix for Win32 compile #jira UE-33349 Change 3052536 on 2016/07/15 by Uriel.Doyon Fixed texture streaming overbudget warning when using per texture bias. [CL 3054554 by Gil Gribb in Main branch]
1474 lines
59 KiB
C++
1474 lines
59 KiB
C++
// 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"
|
|
#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"
|
|
#include "DistanceFieldSurfaceCacheLighting.h"
|
|
#include "GlobalDistanceField.h"
|
|
#include "PostProcess/PostProcessing.h"
|
|
#include "DistanceFieldAtlas.h"
|
|
#include "EngineModule.h"
|
|
#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
|
|
);
|
|
|
|
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);
|
|
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("");
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
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
|
|
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();
|
|
|
|
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:
|
|
{
|
|
TShaderMapRef<TOneColorPixelShaderMRT<5> > MRTPixelShader(ShaderMap);
|
|
PixelShader = *MRTPixelShader;
|
|
}
|
|
break;
|
|
case 6:
|
|
{
|
|
TShaderMapRef<TOneColorPixelShaderMRT<6> > MRTPixelShader(ShaderMap);
|
|
PixelShader = *MRTPixelShader;
|
|
}
|
|
break;
|
|
default:
|
|
case 1:
|
|
{
|
|
TShaderMapRef<TOneColorPixelShaderMRT<1> > MRTPixelShader(ShaderMap);
|
|
PixelShader = *MRTPixelShader;
|
|
}
|
|
break;
|
|
}
|
|
|
|
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
|
|
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 )
|
|
};
|
|
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);
|
|
|
|
// 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);
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
// clearing the GBuffer
|
|
FSceneRenderTargets::Get(RHICmdList).BeginRenderingGBuffer(RHICmdList, ERenderTargetLoadAction::EClear, DepthLoadAction, View.Family->EngineShowFlags.ShaderComplexity, ClearColor);
|
|
}
|
|
|
|
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.
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_UpdateDownsampledDepthSurface);
|
|
UpdateDownsampledDepthSurface(RHICmdList);
|
|
}
|
|
|
|
// 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() );
|
|
|
|
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;
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo& View = Views[ViewIndex];
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
|
|
const uint32 bSSR = ShouldRenderScreenSpaceReflections( View );
|
|
|
|
if (bSSAO || bHZBOcclusion || bSSR)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
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()
|
|
{
|
|
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);
|
|
|
|
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)
|
|
{
|
|
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);
|
|
|
|
{
|
|
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);
|
|
#if !UE_BUILD_SHIPPING
|
|
if (CVarStallInitViews.GetValueOnRenderThread() > 0.0f)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_InitViews_Intentional_Stall);
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (ShouldPrepareDistanceFields())
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_DistanceFieldAO_Init);
|
|
GDistanceFieldVolumeTextureAtlas.UpdateAllocations();
|
|
UpdateGlobalDistanceFieldObjectBuffers(RHICmdList);
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (GRHIThread)
|
|
{
|
|
// we will probably stall on occlusion queries, so might as well have the RHI thread and GPU work while we wait.
|
|
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
|
|
|
|
|
|
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();
|
|
}
|
|
}
|
|
{
|
|
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)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_FXSystem_PreRender);
|
|
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_FXPreRender));
|
|
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();
|
|
{
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_DBuffer);
|
|
SceneContext.ResolveSceneDepthTexture(RHICmdList);
|
|
SceneContext.ResolveSceneDepthToAuxiliaryTexture(RHICmdList);
|
|
|
|
// 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);
|
|
|
|
GCompositionLighting.ProcessBeforeBasePass(RHICmdList, Views[ViewIndex]);
|
|
}
|
|
//GBuffer pass will want to write to SceneDepthZ
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, SceneContext.GetSceneDepthTexture());
|
|
ServiceLocalQueue();
|
|
}
|
|
|
|
// Clear the G Buffer render targets
|
|
bool bIsGBufferCurrent = false;
|
|
if (bRequiresRHIClear)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_SetAndClearViewGBuffer);
|
|
// 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();
|
|
}
|
|
|
|
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);
|
|
}
|
|
else if (!bIsGBufferCurrent)
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
{
|
|
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();
|
|
}
|
|
|
|
{
|
|
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))
|
|
{
|
|
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);
|
|
}
|
|
|
|
// Pre-lighting composition lighting stage
|
|
// e.g. deferred decals, SSAO
|
|
if (FeatureLevel >= ERHIFeatureLevel::SM4)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_AfterBasePass);
|
|
|
|
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();
|
|
}
|
|
|
|
{
|
|
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)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_Lighting);
|
|
|
|
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();
|
|
|
|
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();
|
|
|
|
// SSS need the SceneColor finalized as an SRV.
|
|
SceneContext.FinishRenderingSceneColor(RHICmdList, true);
|
|
|
|
// Render reflections that only operate on opaque pixels
|
|
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)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_RenderLightShaftOcclusion);
|
|
RenderLightShaftOcclusion(RHICmdList, LightShaftOutput);
|
|
ServiceLocalQueue();
|
|
}
|
|
|
|
// Draw atmosphere
|
|
if (ShouldRenderAtmosphere(ViewFamily))
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
|
|
GRenderTargetPool.AddPhaseEvent(TEXT("Fog"));
|
|
|
|
// Draw fog.
|
|
if (ShouldRenderFog(ViewFamily))
|
|
{
|
|
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);
|
|
}
|
|
|
|
SceneContext.FinishRenderingSceneColor(RHICmdList, true);
|
|
}
|
|
|
|
// No longer needed, release
|
|
LightShaftOutput.LightShaftOcclusion = NULL;
|
|
|
|
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();
|
|
|
|
if(GetRefractionQuality(ViewFamily) > 0)
|
|
{
|
|
// 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)
|
|
{
|
|
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)
|
|
{
|
|
// 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;
|
|
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();
|
|
}
|
|
|
|
if (ViewFamily.EngineShowFlags.VisualizeMeshDistanceFields)
|
|
{
|
|
RenderMeshDistanceFieldVisualization(RHICmdList, FDistanceFieldAOParameters(Scene->DefaultMaxDistanceFieldOcclusionDistance));
|
|
ServiceLocalQueue();
|
|
}
|
|
|
|
// 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);
|
|
|
|
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_PostProcessing));
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
|
|
|
|
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);
|
|
}
|
|
|
|
//grab the new transform out of the proxies for next frame
|
|
if (VelocityRT)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FDeferredShadingSceneRenderer_UpdateMotionBlurCache);
|
|
Scene->MotionBlurInfoData.UpdateMotionBlurCache(Scene);
|
|
}
|
|
|
|
VelocityRT.SafeRelease();
|
|
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
|
|
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);
|
|
}
|
|
}
|