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 3055495 on 2016/07/19 by Marc.Olano Allow Noise material node on mobile No reason to exclude mobile, except for Fast Gradient Noise, which uses 3D textures. Allow this node on ES2 for all of the other noise functions. #jira UE-33345 Change 3055602 on 2016/07/19 by Luke.Thatcher Fix crash bug in D3D11 RHI when selecting adapters. - Array of adapter descriptors will get out of sync with the adapter index if any adapter is skipped (e.g. the Microsoft Basic Render Device). #jira UE-33236 Change 3055890 on 2016/07/19 by Daniel.Wright Improved the assert in LoadModuleChecked so we won't have to check the log to see which module it was Change 3055891 on 2016/07/19 by Daniel.Wright Fixed Global Distance Field not dirtying previous object position on UpdateTransform - left behind a phantom shadow on teleports * This will effectively double partial distiance field update costs until clipping of the update regions is implemented Change 3055892 on 2016/07/19 by Daniel.Wright Higher poly light source shapes drawn into reflection captures Change 3055893 on 2016/07/19 by Daniel.Wright More info to 'Incompatible surface format' GNM assert Change 3055904 on 2016/07/19 by Daniel.Wright Reflection environment normalization improvements * Indirect specular from reflection captures is now mixed with indirect diffuse from lightmaps based on roughness, such that a mirror surface will have no mixing. Reflection captures now match other reflection methods like SSR and planar reflections much more closely. * When a stationary skylight is present, Reflection captures are now normalized as if the initial skylight will always be present, giving consistent results with static skylight reflections. The skylight and reflection captures with sky removed used to be normalized separately, compacting the relative brightness between the sky and scene. * Added r.ReflectionEnvironmentLightmapMixing for debugging lightmap mixing issues. This toggle was previously not possible due to prenormalizing the capture data. * The standard deferred reflection path (r.DoTiledReflections 0) can no longer match the results of the compute path or base pass reflections, as it would require MRT to accumulate the average brightness * Removed unused r.DiffuseFromCaptures * Cost of reflection environment on PS4 increased from 1.52ms -> 1.75ms with this change, but decreased back to 1.58ms by reducing tile size to 8x8 Change 3055905 on 2016/07/19 by Daniel.Wright Workaround for RTDF shadows not working on PS4 - manual clear of ObjectIndirectArguments instead of RHICmdList.ClearUAV Change 3059486 on 2016/07/21 by Nick.Penwarden Testing #uecritical Change 3060558 on 2016/07/21 by Daniel.Wright Fixed skylight with specified cubemap being black Change 3061999 on 2016/07/22 by Marcus.Wassmer Disable old AMD driver hacks for DX11. QA has already tested with them off and given thumbs up. Change 3062241 on 2016/07/22 by Daniel.Wright Fixed bug in RHISupportsSeparateMSAAAndResolveTextures that was preventing MSAA for any non-Vulkan platforms Change 3062244 on 2016/07/22 by Daniel.Wright Discard old prenormalized reflection environment data on load Change 3062283 on 2016/07/22 by Daniel.Wright MSAA support for the forward renderer * AntiAliasing method is chosen in Rendering project settings, DefaultSettings category * Deferred passes like shadow projection, fogging and decals are only computed per-pixel and can introduce aliasing * Added Rendering project setting VertexFoggingForOpaque, which makes height fog cheaper and work properly with MSAA * The AntiAliasing method in PostProcessSettings has been removed, this may affect existing content * Added r.MSAACount which defaults to 4 * Integrated wide custom resolve filter from Oculus renderer, controlled by r.WideCustomResolve * GBuffer targets are no longer allocated when using the forward renderer * Decal blend modes that write to the GBuffer fall back to SceneColor emissive only Change 3062666 on 2016/07/23 by Uriel.Doyon Added legend to streaming accuracy viewmodes Added a new helper class FRenderTargetTemp to be reused in different canvas rendering. Exposed the pass through pixel shader so that it can be reused. #review-3058986 @marcus.wassmer Change 3063023 on 2016/07/25 by Luke.Thatcher Fix "RecompileShaders Changed" when using Cook On The Fly. #jira UE-33573 Change 3063078 on 2016/07/25 by Ben.Woodhouse Add -emitdrawevents command line option to emit draw events by default. This is useful when capturing with Renderdoc Change 3063315 on 2016/07/25 by Ben.Woodhouse Fix div 0 in motion blur. This caused artifacts in some fairly common cases #jira UE-32331 Change 3063897 on 2016/07/25 by Uriel.Doyon Fixed missing qualifier on interpolants Change 3064559 on 2016/07/26 by Ben.Woodhouse Fix for cooker crash with BC6H textures (XB1, but may affect other platforms). Also fixes corruption issue with texture slices not being a multiple of 4 pixels (expanding as necessary), courtesy of Stu McKenna at the Coalition Tested fix on xbox, PC and PS4, using QAGame #jira UE-28592 Change 3064896 on 2016/07/26 by Ben.Woodhouse Fix compile errors on PS4 (the variable "sample" was conflicting with a keyword, causing compile errors). Also making encoding consistent on new shaders (ansi rather than UTF16) Change 3064913 on 2016/07/26 by Ben.Marsh Fix spelling of "Editor, Tools, Monolithics & DDC" node in Dev-Rendering build settings. Change 3065326 on 2016/07/26 by Uriel.Doyon Fixed UnbuiltInstanceBoundsList not being reset correctly, creating broken rendered primitives. #jira UE-32585 Change 3065541 on 2016/07/26 by Daniel.Wright Materials with a GBuffer SceneTexture lookup will fail to compile with forward shading Change 3065543 on 2016/07/26 by Daniel.Wright Restored DetailMode changes causing a FGlobalComponentRecreateRenderStateContext - accidental removal from cl 2969413 Change 3065545 on 2016/07/26 by Daniel.Wright Added material property bNormalCurvatureToRoughness, which can slightly reduce aliasing. Tweakable impact with r.NormalCurvatureToRoughnessScale. Fixed reflection capture feedback with base pass reflections Change 3066783 on 2016/07/27 by Daniel.Wright Moved PreShadowCacheDepthZ out of FSceneRenderTargets and into FScene, which fixes issues with cached preshadows and multiple scenes, including HighResScreenShot Disabled GMinScreenRadiusForShadowCaster on per-object shadows, which fixes popping when trying to increase shadow resolution from the defaults (r.Shadow.TexelsPerPixel 3) Change 3066794 on 2016/07/27 by Daniel.Wright Fixed crash rendering planar reflections due to NULL PostProcessSettings Change 3067412 on 2016/07/27 by Daniel.Wright Fix for OpenGL4 with uint interpolator Change 3068470 on 2016/07/28 by Daniel.Wright Fixed crash rendering translucency with translucent shadows which were determined to be invisible Change 3069046 on 2016/07/28 by Daniel.Wright Handle null Family in SetupAntiAliasingMethod Change 3069059 on 2016/07/28 by Daniel.Wright Added r.ReflectionEnvironmentBeginMixingRoughness (.1) and r.ReflectionEnvironmentEndMixingRoughness (.3), which can be used to tweak the lightmap mixing heuristc, or revert to previous behavior (mixing even on a mirror surface) Change 3069391 on 2016/07/28 by Daniel.Wright Fixed AverageBrightness being applied to reflections in gamma space in the mobile base pass, causing ES2 reflections to be overbright Change 3070369 on 2016/07/29 by Daniel.Wright r.ReflectionEnvironmentBeginMixingRoughness and r.ReflectionEnvironmentEndMixingRoughness set to 0 can be used to achieve old non-roughness based lightmap mixing Change 3070370 on 2016/07/29 by Daniel.Wright Bumped reflection capture DDC version to get rid of legacy prenormalized data Change 3070680 on 2016/07/29 by Marcus.Wassmer Fix slate ensure that is most likely a timing issue exposed by rendering. #ue-33902 Change 3070811 on 2016/07/29 by Marcus.Wassmer Fix ProjectLauncher errors when loading old versions #ue-33939 Change 3070971 on 2016/07/29 by Uriel.Doyon Updated ListTextures outputs to fix cooked VS non cooked differences and also to put enphasis on disk VS memory Change 3071452 on 2016/07/31 by Uriel.Doyon Updated the legend description for the (texture streaming) primitive distance accuracy view mode [CL 3072803 by Marcus Wassmer in Main branch]
1477 lines
59 KiB
C++
1477 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();
|
|
|
|
SceneContext.ResolveSceneDepthTexture(RHICmdList);
|
|
|
|
const bool bShouldRenderVelocities = ShouldRenderVelocities();
|
|
const bool bUseVelocityGBuffer = FVelocityRendering::OutputsToGBuffer();
|
|
const bool bUseSelectiveBasePassOutputs = UseSelectiveBasePassOutputs();
|
|
|
|
if (bUseGBuffer)
|
|
{
|
|
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.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;
|
|
}
|
|
|
|
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));
|
|
|
|
if (bUseGBuffer)
|
|
{
|
|
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.GBufferA ? SceneContext.GetGBufferATexture() : NULL
|
|
);
|
|
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);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|