You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rnx #rb none #ROBOMERGE-OWNER: ryan.vance #ROBOMERGE-AUTHOR: kevin.ortegren #ROBOMERGE-SOURCE: CL 5935725 via CL 5935820 via CL 5935821 #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 5948806 by kevin ortegren in Dev-VR branch]
1883 lines
76 KiB
C++
1883 lines
76 KiB
C++
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
ShadowDepthRendering.cpp: Shadow depth rendering implementation
|
|
=============================================================================*/
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Stats/Stats.h"
|
|
#include "Misc/MemStack.h"
|
|
#include "RHIDefinitions.h"
|
|
#include "HAL/IConsoleManager.h"
|
|
#include "Async/TaskGraphInterfaces.h"
|
|
#include "RHI.h"
|
|
#include "HitProxies.h"
|
|
#include "ShaderParameters.h"
|
|
#include "RenderResource.h"
|
|
#include "RendererInterface.h"
|
|
#include "PrimitiveViewRelevance.h"
|
|
#include "UniformBuffer.h"
|
|
#include "Shader.h"
|
|
#include "StaticBoundShaderState.h"
|
|
#include "SceneUtils.h"
|
|
#include "Materials/Material.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "PostProcess/SceneRenderTargets.h"
|
|
#include "GlobalShader.h"
|
|
#include "MaterialShaderType.h"
|
|
#include "MaterialShader.h"
|
|
#include "MeshMaterialShader.h"
|
|
#include "ShaderBaseClasses.h"
|
|
#include "ShadowRendering.h"
|
|
#include "SceneRendering.h"
|
|
#include "LightPropagationVolume.h"
|
|
#include "ScenePrivate.h"
|
|
#include "PostProcess/SceneFilterRendering.h"
|
|
#include "ScreenRendering.h"
|
|
#include "ClearQuad.h"
|
|
#include "PipelineStateCache.h"
|
|
#include "MeshPassProcessor.inl"
|
|
#include "VisualizeTexture.h"
|
|
#include "GPUScene.h"
|
|
|
|
DECLARE_GPU_STAT_NAMED(ShadowDepths, TEXT("Shadow Depths"));
|
|
|
|
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FShadowDepthPassUniformParameters, "ShadowDepthPass");
|
|
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FMobileShadowDepthPassUniformParameters, "MobileShadowDepthPass");
|
|
|
|
void SetupShadowDepthPassUniformBuffer(
|
|
const FProjectedShadowInfo* ShadowInfo,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FViewInfo& View,
|
|
FShadowDepthPassUniformParameters& ShadowDepthPassParameters)
|
|
{
|
|
FSceneRenderTargets& SceneRenderTargets = FSceneRenderTargets::Get(RHICmdList);
|
|
SetupSceneTextureUniformParameters(SceneRenderTargets, View.FeatureLevel, ESceneTextureSetupMode::None, ShadowDepthPassParameters.SceneTextures);
|
|
|
|
ShadowDepthPassParameters.ProjectionMatrix = FTranslationMatrix(ShadowInfo->PreShadowTranslation - View.ViewMatrices.GetPreViewTranslation()) * ShadowInfo->SubjectAndReceiverMatrix;
|
|
|
|
ShadowDepthPassParameters.ShadowParams = FVector2D(ShadowInfo->GetShaderDepthBias(), ShadowInfo->InvMaxSubjectDepth);
|
|
// Only clamp vertices to the near plane when rendering whole scene directional light shadow depths or preshadows from directional lights
|
|
const bool bClampToNearPlaneValue = ShadowInfo->IsWholeSceneDirectionalShadow() || (ShadowInfo->bPreShadow && ShadowInfo->bDirectionalLight);
|
|
ShadowDepthPassParameters.bClampToNearPlane = bClampToNearPlaneValue ? 1.0f : 0.0f;
|
|
|
|
if (ShadowInfo->bOnePassPointLightShadow)
|
|
{
|
|
const FMatrix Translation = FTranslationMatrix(-View.ViewMatrices.GetPreViewTranslation());
|
|
|
|
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
|
|
{
|
|
// Have to apply the pre-view translation to the view - projection matrices
|
|
FMatrix TranslatedShadowViewProjectionMatrix = Translation * ShadowInfo->OnePassShadowViewProjectionMatrices[FaceIndex];
|
|
ShadowDepthPassParameters.ShadowViewProjectionMatrices[FaceIndex] = TranslatedShadowViewProjectionMatrix;
|
|
}
|
|
}
|
|
|
|
if (ShadowInfo->bReflectiveShadowmap)
|
|
{
|
|
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
|
|
|
|
if (ViewState)
|
|
{
|
|
const FLightPropagationVolume* Lpv = ViewState->GetLightPropagationVolume(View.GetFeatureLevel());
|
|
|
|
if (Lpv)
|
|
{
|
|
ShadowDepthPassParameters.LPV = Lpv->GetWriteUniformBufferParams();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetupShadowDepthPassUniformBuffer(
|
|
const FProjectedShadowInfo* ShadowInfo,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FViewInfo& View,
|
|
FMobileShadowDepthPassUniformParameters& ShadowDepthPassParameters)
|
|
{
|
|
FSceneRenderTargets& SceneRenderTargets = FSceneRenderTargets::Get(RHICmdList);
|
|
SetupMobileSceneTextureUniformParameters(SceneRenderTargets, View.FeatureLevel, false, ShadowDepthPassParameters.SceneTextures);
|
|
|
|
ShadowDepthPassParameters.ProjectionMatrix = FTranslationMatrix(ShadowInfo->PreShadowTranslation - View.ViewMatrices.GetPreViewTranslation()) * ShadowInfo->SubjectAndReceiverMatrix;
|
|
|
|
ShadowDepthPassParameters.ShadowParams = FVector2D(ShadowInfo->GetShaderDepthBias(), ShadowInfo->InvMaxSubjectDepth);
|
|
// Only clamp vertices to the near plane when rendering whole scene directional light shadow depths or preshadows from directional lights
|
|
const bool bClampToNearPlaneValue = ShadowInfo->IsWholeSceneDirectionalShadow() || (ShadowInfo->bPreShadow && ShadowInfo->bDirectionalLight);
|
|
ShadowDepthPassParameters.bClampToNearPlane = bClampToNearPlaneValue ? 1.0f : 0.0f;
|
|
}
|
|
|
|
class FShadowDepthShaderElementData : public FMeshMaterialShaderElementData
|
|
{
|
|
public:
|
|
|
|
int32 LayerId;
|
|
};
|
|
|
|
/**
|
|
* A vertex shader for rendering the depth of a mesh.
|
|
*/
|
|
class FShadowDepthVS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FShadowDepthVS, MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
FShadowDepthVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FMeshMaterialShader(Initializer)
|
|
{
|
|
const ERHIFeatureLevel::Type FeatureLevel = GetMaxSupportedFeatureLevel((EShaderPlatform)Initializer.Target.Platform);
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FMobileShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
|
|
LayerId.Bind(Initializer.ParameterMap, TEXT("LayerId"));
|
|
}
|
|
|
|
FShadowDepthVS() {}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
Ar << LayerId;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
void GetShaderBindings(
|
|
const FScene* Scene,
|
|
ERHIFeatureLevel::Type FeatureLevel,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
const FMaterialRenderProxy& MaterialRenderProxy,
|
|
const FMaterial& Material,
|
|
const FMeshPassProcessorRenderState& DrawRenderState,
|
|
const FShadowDepthShaderElementData& ShaderElementData,
|
|
FMeshDrawSingleShaderBindings& ShaderBindings) const
|
|
{
|
|
FMeshMaterialShader::GetShaderBindings(Scene, FeatureLevel, PrimitiveSceneProxy, MaterialRenderProxy, Material, DrawRenderState, ShaderElementData, ShaderBindings);
|
|
|
|
ShaderBindings.Add(LayerId, ShaderElementData.LayerId);
|
|
}
|
|
|
|
private:
|
|
FShaderParameter LayerId;
|
|
};
|
|
|
|
enum EShadowDepthVertexShaderMode
|
|
{
|
|
VertexShadowDepth_PerspectiveCorrect,
|
|
VertexShadowDepth_OutputDepth,
|
|
VertexShadowDepth_OnePassPointLight
|
|
};
|
|
|
|
static TAutoConsoleVariable<int32> CVarSupportPointLightWholeSceneShadows(
|
|
TEXT("r.SupportPointLightWholeSceneShadows"),
|
|
1,
|
|
TEXT("Enables shadowcasting point lights."),
|
|
ECVF_ReadOnly | ECVF_RenderThreadSafe);
|
|
|
|
/**
|
|
* A vertex shader for rendering the depth of a mesh.
|
|
*/
|
|
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap, bool bUsePositionOnlyStream, bool bIsForGeometryShader = false>
|
|
class TShadowDepthVS : public FShadowDepthVS
|
|
{
|
|
DECLARE_SHADER_TYPE(TShadowDepthVS, MeshMaterial);
|
|
public:
|
|
|
|
TShadowDepthVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FShadowDepthVS(Initializer)
|
|
{
|
|
}
|
|
|
|
TShadowDepthVS() {}
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
static const auto SupportAllShaderPermutationsVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportAllShaderPermutations"));
|
|
const bool bForceAllPermutations = SupportAllShaderPermutationsVar && SupportAllShaderPermutationsVar->GetValueOnAnyThread() != 0;
|
|
const bool bSupportPointLightWholeSceneShadows = CVarSupportPointLightWholeSceneShadows.GetValueOnAnyThread() != 0 || bForceAllPermutations;
|
|
const bool bRHISupportsShadowCastingPointLights = RHISupportsGeometryShaders(Platform) || RHISupportsVertexShaderLayer(Platform);
|
|
|
|
if (bIsForGeometryShader && (!bSupportPointLightWholeSceneShadows || !bRHISupportsShadowCastingPointLights))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
|
|
// Compile for special engine materials.
|
|
if (bRenderReflectiveShadowMap)
|
|
{
|
|
// Reflective shadow map shaders must be compiled for every material because they access the material normal
|
|
return !bUsePositionOnlyStream
|
|
// Don't render ShadowDepth for translucent unlit materials, unless we're injecting emissive
|
|
&& (Material->ShouldCastDynamicShadows() || Material->ShouldInjectEmissiveIntoLPV()
|
|
|| Material->ShouldBlockGI())
|
|
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
else
|
|
{
|
|
return (Material->IsSpecialEngineMaterial()
|
|
// Masked and WPO materials need their shaders but cannot be used with a position only stream.
|
|
|| ((!Material->WritesEveryPixel(true) || Material->MaterialMayModifyMeshPosition()) && !bUsePositionOnlyStream))
|
|
// Only compile one pass point light shaders for feature levels >= SM4
|
|
&& (ShaderMode != VertexShadowDepth_OnePassPointLight || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
|
|
// Only compile position-only shaders for vertex factories that support it.
|
|
&& (!bUsePositionOnlyStream || VertexFactoryType->SupportsPositionOnly())
|
|
// Don't render ShadowDepth for translucent unlit materials
|
|
&& Material->ShouldCastDynamicShadows()
|
|
// Only compile perspective correct light shaders for feature levels >= SM4
|
|
&& (ShaderMode != VertexShadowDepth_PerspectiveCorrect || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4));
|
|
}
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FShadowDepthVS::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == VertexShadowDepth_PerspectiveCorrect));
|
|
OutEnvironment.SetDefine(TEXT("ONEPASS_POINTLIGHT_SHADOW"), (uint32)(ShaderMode == VertexShadowDepth_OnePassPointLight));
|
|
OutEnvironment.SetDefine(TEXT("REFLECTIVE_SHADOW_MAP"), (uint32)bRenderReflectiveShadowMap);
|
|
OutEnvironment.SetDefine(TEXT("POSITION_ONLY"), (uint32)bUsePositionOnlyStream);
|
|
|
|
if (bIsForGeometryShader)
|
|
{
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_VertexToGeometryShader);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* A Hull shader for rendering the depth of a mesh.
|
|
*/
|
|
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
|
|
class TShadowDepthHS : public FBaseHS
|
|
{
|
|
DECLARE_SHADER_TYPE(TShadowDepthHS, MeshMaterial);
|
|
public:
|
|
|
|
|
|
TShadowDepthHS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FBaseHS(Initializer)
|
|
{}
|
|
|
|
TShadowDepthHS() {}
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
// Re-use ShouldCache from vertex shader
|
|
return FBaseHS::ShouldCompilePermutation(Platform, Material, VertexFactoryType)
|
|
&& TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ShouldCompilePermutation(Platform, Material, VertexFactoryType);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
// Re-use compilation env from vertex shader
|
|
|
|
TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* A Domain shader for rendering the depth of a mesh.
|
|
*/
|
|
template <EShadowDepthVertexShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
|
|
class TShadowDepthDS : public FBaseDS
|
|
{
|
|
DECLARE_SHADER_TYPE(TShadowDepthDS, MeshMaterial);
|
|
public:
|
|
|
|
TShadowDepthDS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FBaseDS(Initializer)
|
|
{
|
|
const ERHIFeatureLevel::Type FeatureLevel = GetMaxSupportedFeatureLevel((EShaderPlatform)Initializer.Target.Platform);
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FMobileShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
}
|
|
|
|
TShadowDepthDS() {}
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
// Re-use ShouldCache from vertex shader
|
|
return FBaseDS::ShouldCompilePermutation(Platform, Material, VertexFactoryType)
|
|
&& TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ShouldCompilePermutation(Platform, Material, VertexFactoryType);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
// Re-use compilation env from vertex shader
|
|
TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
}
|
|
};
|
|
|
|
/** Geometry shader that allows one pass point light shadows by cloning triangles to all faces of the cube map. */
|
|
class FOnePassPointShadowDepthGS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FOnePassPointShadowDepthGS, MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return RHISupportsGeometryShaders(Platform) && TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true>::ShouldCompilePermutation(Platform, Material, VertexFactoryType);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FMeshMaterialShader::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
}
|
|
|
|
FOnePassPointShadowDepthGS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FMeshMaterialShader(Initializer)
|
|
{
|
|
const ERHIFeatureLevel::Type FeatureLevel = GetMaxSupportedFeatureLevel((EShaderPlatform)Initializer.Target.Platform);
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FMobileShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
}
|
|
|
|
FOnePassPointShadowDepthGS() {}
|
|
};
|
|
|
|
#define IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(ShaderMode,bRenderReflectiveShadowMap) \
|
|
typedef TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false> TShadowDepthVS##ShaderMode##bRenderReflectiveShadowMap; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVS##ShaderMode##bRenderReflectiveShadowMap,TEXT("/Engine/Private/ShadowDepthVertexShader.usf"),TEXT("Main"),SF_Vertex); \
|
|
typedef TShadowDepthVS<ShaderMode, bRenderReflectiveShadowMap, false, true> TShadowDepthVSForGS##ShaderMode##bRenderReflectiveShadowMap; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthVSForGS##ShaderMode##bRenderReflectiveShadowMap,TEXT("/Engine/Private/ShadowDepthVertexShader.usf"),TEXT("MainForGS"),SF_Vertex); \
|
|
typedef TShadowDepthHS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthHS##ShaderMode##bRenderReflectiveShadowMap; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthHS##ShaderMode##bRenderReflectiveShadowMap,TEXT("/Engine/Private/ShadowDepthVertexShader.usf"),TEXT("MainHull"),SF_Hull); \
|
|
typedef TShadowDepthDS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthDS##ShaderMode##bRenderReflectiveShadowMap; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthDS##ShaderMode##bRenderReflectiveShadowMap,TEXT("/Engine/Private/ShadowDepthVertexShader.usf"),TEXT("MainDomain"),SF_Domain);
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FOnePassPointShadowDepthGS, TEXT("/Engine/Private/ShadowDepthVertexShader.usf"), TEXT("MainOnePassPointLightGS"), SF_Geometry);
|
|
|
|
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_PerspectiveCorrect, true);
|
|
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_PerspectiveCorrect, false);
|
|
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OutputDepth, true);
|
|
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OutputDepth, false);
|
|
IMPLEMENT_SHADOW_DEPTH_SHADERMODE_SHADERS(VertexShadowDepth_OnePassPointLight, false);
|
|
|
|
// Position only vertex shaders.
|
|
typedef TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, true> TShadowDepthVSVertexShadowDepth_PerspectiveCorrectPositionOnly;
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>, TShadowDepthVSVertexShadowDepth_PerspectiveCorrectPositionOnly, TEXT("/Engine/Private/ShadowDepthVertexShader.usf"), TEXT("PositionOnlyMain"), SF_Vertex);
|
|
typedef TShadowDepthVS<VertexShadowDepth_OutputDepth, false, true> TShadowDepthVSVertexShadowDepth_OutputDepthPositionOnly;
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>, TShadowDepthVSVertexShadowDepth_OutputDepthPositionOnly, TEXT("/Engine/Private/ShadowDepthVertexShader.usf"), TEXT("PositionOnlyMain"), SF_Vertex);
|
|
typedef TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true> TShadowDepthVSVertexShadowDepth_OnePassPointLightPositionOnly;
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>, TShadowDepthVSVertexShadowDepth_OnePassPointLightPositionOnly, TEXT("/Engine/Private/ShadowDepthVertexShader.usf"), TEXT("PositionOnlyMain"), SF_Vertex);
|
|
typedef TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true, true> TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightPositionOnly;
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>, TShadowDepthVSForGSVertexShadowDepth_OnePassPointLightPositionOnly, TEXT("/Engine/Private/ShadowDepthVertexShader.usf"), TEXT("PositionOnlyMainForGS"), SF_Vertex);
|
|
|
|
/**
|
|
* A pixel shader for rendering the depth of a mesh.
|
|
*/
|
|
template <bool bRenderReflectiveShadowMap>
|
|
class TShadowDepthBasePS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(TShadowDepthBasePS, MeshMaterial);
|
|
public:
|
|
|
|
TShadowDepthBasePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FMeshMaterialShader(Initializer)
|
|
{
|
|
GvListBuffer.Bind(Initializer.ParameterMap, TEXT("RWGvListBuffer"));
|
|
GvListHeadBuffer.Bind(Initializer.ParameterMap, TEXT("RWGvListHeadBuffer"));
|
|
VplListBuffer.Bind(Initializer.ParameterMap, TEXT("RWVplListBuffer"));
|
|
VplListHeadBuffer.Bind(Initializer.ParameterMap, TEXT("RWVplListHeadBuffer"));
|
|
|
|
const ERHIFeatureLevel::Type FeatureLevel = GetMaxSupportedFeatureLevel((EShaderPlatform)Initializer.Target.Platform);
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
|
|
{
|
|
PassUniformBuffer.Bind(Initializer.ParameterMap, FMobileShadowDepthPassUniformParameters::StaticStructMetadata.GetShaderVariableName());
|
|
}
|
|
}
|
|
|
|
TShadowDepthBasePS() {}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
|
|
Ar << GvListBuffer;
|
|
Ar << GvListHeadBuffer;
|
|
Ar << VplListBuffer;
|
|
Ar << VplListHeadBuffer;
|
|
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FRWShaderParameter GvListBuffer;
|
|
FRWShaderParameter GvListHeadBuffer;
|
|
FRWShaderParameter VplListBuffer;
|
|
FRWShaderParameter VplListHeadBuffer;
|
|
};
|
|
|
|
enum EShadowDepthPixelShaderMode
|
|
{
|
|
PixelShadowDepth_NonPerspectiveCorrect,
|
|
PixelShadowDepth_PerspectiveCorrect,
|
|
PixelShadowDepth_OnePassPointLight
|
|
};
|
|
|
|
template <EShadowDepthPixelShaderMode ShaderMode, bool bRenderReflectiveShadowMap>
|
|
class TShadowDepthPS : public TShadowDepthBasePS<bRenderReflectiveShadowMap>
|
|
{
|
|
DECLARE_SHADER_TYPE(TShadowDepthPS, MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(EShaderPlatform Platform, const FMaterial* Material, const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
if (!IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
|
|
{
|
|
return (Material->IsSpecialEngineMaterial()
|
|
// Only compile for masked or lit translucent materials
|
|
|| !Material->WritesEveryPixel(true)
|
|
|| (Material->MaterialMayModifyMeshPosition() && Material->IsUsedWithInstancedStaticMeshes())
|
|
// Perspective correct rendering needs a pixel shader and WPO materials can't be overridden with default material.
|
|
|| (ShaderMode == PixelShadowDepth_PerspectiveCorrect && Material->MaterialMayModifyMeshPosition()))
|
|
&& ShaderMode == PixelShadowDepth_NonPerspectiveCorrect
|
|
// Don't render ShadowDepth for translucent unlit materials
|
|
&& Material->ShouldCastDynamicShadows()
|
|
&& !bRenderReflectiveShadowMap;
|
|
}
|
|
|
|
if (bRenderReflectiveShadowMap)
|
|
{
|
|
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
|
|
// Reflective shadow map shaders must be compiled for every material because they access the material normal
|
|
return
|
|
// Only compile one pass point light shaders for feature levels >= SM4
|
|
(Material->ShouldCastDynamicShadows() || Material->ShouldInjectEmissiveIntoLPV() || Material->ShouldBlockGI())
|
|
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
else
|
|
{
|
|
//Note: This logic needs to stay in sync with OverrideWithDefaultMaterialForShadowDepth!
|
|
return (Material->IsSpecialEngineMaterial()
|
|
// Only compile for masked or lit translucent materials
|
|
|| !Material->WritesEveryPixel(true)
|
|
|| (Material->MaterialMayModifyMeshPosition() && Material->IsUsedWithInstancedStaticMeshes())
|
|
// Perspective correct rendering needs a pixel shader and WPO materials can't be overridden with default material.
|
|
|| (ShaderMode == PixelShadowDepth_PerspectiveCorrect && Material->MaterialMayModifyMeshPosition()))
|
|
// Only compile one pass point light shaders for feature levels >= SM4
|
|
&& (ShaderMode != PixelShadowDepth_OnePassPointLight || IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4))
|
|
// Don't render ShadowDepth for translucent unlit materials
|
|
&& Material->ShouldCastDynamicShadows()
|
|
&& IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
TShadowDepthBasePS<bRenderReflectiveShadowMap>::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == PixelShadowDepth_PerspectiveCorrect));
|
|
OutEnvironment.SetDefine(TEXT("ONEPASS_POINTLIGHT_SHADOW"), (uint32)(ShaderMode == PixelShadowDepth_OnePassPointLight));
|
|
OutEnvironment.SetDefine(TEXT("REFLECTIVE_SHADOW_MAP"), (uint32)bRenderReflectiveShadowMap);
|
|
}
|
|
|
|
TShadowDepthPS()
|
|
{
|
|
}
|
|
|
|
TShadowDepthPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: TShadowDepthBasePS<bRenderReflectiveShadowMap>(Initializer)
|
|
{
|
|
}
|
|
};
|
|
|
|
// typedef required to get around macro expansion failure due to commas in template argument list for TShadowDepthPixelShader
|
|
#define IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(ShaderMode, bRenderReflectiveShadowMap) \
|
|
typedef TShadowDepthPS<ShaderMode, bRenderReflectiveShadowMap> TShadowDepthPS##ShaderMode##bRenderReflectiveShadowMap; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TShadowDepthPS##ShaderMode##bRenderReflectiveShadowMap,TEXT("/Engine/Private/ShadowDepthPixelShader.usf"),TEXT("Main"),SF_Pixel);
|
|
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_NonPerspectiveCorrect, true);
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_NonPerspectiveCorrect, false);
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_PerspectiveCorrect, true);
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_PerspectiveCorrect, false);
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_OnePassPointLight, true);
|
|
IMPLEMENT_SHADOWDEPTHPASS_PIXELSHADER_TYPE(PixelShadowDepth_OnePassPointLight, false);
|
|
|
|
/**
|
|
* Overrides a material used for shadow depth rendering with the default material when appropriate.
|
|
* Overriding in this manner can reduce state switches and the number of shaders that have to be compiled.
|
|
* This logic needs to stay in sync with shadow depth shader ShouldCache logic.
|
|
*/
|
|
void OverrideWithDefaultMaterialForShadowDepth(
|
|
const FMaterialRenderProxy*& InOutMaterialRenderProxy,
|
|
const FMaterial*& InOutMaterialResource,
|
|
bool bReflectiveShadowmap,
|
|
ERHIFeatureLevel::Type InFeatureLevel)
|
|
{
|
|
// Override with the default material when possible.
|
|
if (InOutMaterialResource->WritesEveryPixel(true) && // Don't override masked materials.
|
|
!InOutMaterialResource->MaterialModifiesMeshPosition_RenderThread() && // Don't override materials using world position offset.
|
|
!bReflectiveShadowmap) // Don't override when rendering reflective shadow maps.
|
|
{
|
|
const FMaterialRenderProxy* DefaultProxy = UMaterial::GetDefaultMaterial(MD_Surface)->GetRenderProxy();
|
|
const FMaterial* DefaultMaterialResource = DefaultProxy->GetMaterial(InFeatureLevel);
|
|
|
|
// Override with the default material for opaque materials that don't modify mesh position.
|
|
InOutMaterialRenderProxy = DefaultProxy;
|
|
InOutMaterialResource = DefaultMaterialResource;
|
|
}
|
|
}
|
|
|
|
template <bool bRenderingReflectiveShadowMaps>
|
|
void GetShadowDepthPassShaders(
|
|
const FMaterial& Material,
|
|
const FVertexFactory* VertexFactory,
|
|
ERHIFeatureLevel::Type FeatureLevel,
|
|
bool bDirectionalLight,
|
|
bool bOnePassPointLightShadow,
|
|
bool bPositionOnlyVS,
|
|
FShadowDepthVS*& VertexShader,
|
|
FBaseHS*& HullShader,
|
|
FBaseDS*& DomainShader,
|
|
TShadowDepthBasePS<bRenderingReflectiveShadowMaps>*& PixelShader,
|
|
FOnePassPointShadowDepthGS*& GeometryShader)
|
|
{
|
|
check(!bOnePassPointLightShadow || !bRenderingReflectiveShadowMaps);
|
|
|
|
// Use perspective correct shadow depths for shadow types which typically render low poly meshes into the shadow depth buffer.
|
|
// Depth will be interpolated to the pixel shader and written out, which disables HiZ and double speed Z.
|
|
// Directional light shadows use an ortho projection and can use the non-perspective correct path without artifacts.
|
|
// One pass point lights don't output a linear depth, so they are already perspective correct.
|
|
const bool bUsePerspectiveCorrectShadowDepths = !bDirectionalLight && !bOnePassPointLightShadow;
|
|
|
|
HullShader = nullptr;
|
|
DomainShader = nullptr;
|
|
GeometryShader = nullptr;
|
|
|
|
FVertexFactoryType* VFType = VertexFactory->GetType();
|
|
|
|
const bool bInitializeTessellationShaders =
|
|
Material.GetTessellationMode() != MTM_NoTessellation
|
|
&& RHISupportsTessellation(GShaderPlatformForFeatureLevel[FeatureLevel])
|
|
&& VFType->SupportsTessellationShaders();
|
|
|
|
// Vertex related shaders
|
|
if (bOnePassPointLightShadow)
|
|
{
|
|
if (bPositionOnlyVS)
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, true, true> >(VFType);
|
|
}
|
|
else
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_OnePassPointLight, false, false, true> >(VFType);
|
|
}
|
|
|
|
if (RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[FeatureLevel]))
|
|
{
|
|
// Use the geometry shader which will clone output triangles to all faces of the cube map
|
|
GeometryShader = Material.GetShader<FOnePassPointShadowDepthGS>(VFType);
|
|
}
|
|
|
|
if (bInitializeTessellationShaders)
|
|
{
|
|
HullShader = Material.GetShader<TShadowDepthHS<VertexShadowDepth_OnePassPointLight, false> >(VFType);
|
|
DomainShader = Material.GetShader<TShadowDepthDS<VertexShadowDepth_OnePassPointLight, false> >(VFType);
|
|
}
|
|
}
|
|
else if (bUsePerspectiveCorrectShadowDepths)
|
|
{
|
|
if (bRenderingReflectiveShadowMaps)
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, true, false> >(VFType);
|
|
}
|
|
else
|
|
{
|
|
if (bPositionOnlyVS)
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, true> >(VFType);
|
|
}
|
|
else
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_PerspectiveCorrect, false, false> >(VFType);
|
|
}
|
|
}
|
|
|
|
if (bInitializeTessellationShaders)
|
|
{
|
|
HullShader = Material.GetShader<TShadowDepthHS<VertexShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
|
|
DomainShader = Material.GetShader<TShadowDepthDS<VertexShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bRenderingReflectiveShadowMaps)
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, true, false> >(VFType);
|
|
|
|
if (bInitializeTessellationShaders)
|
|
{
|
|
HullShader = Material.GetShader<TShadowDepthHS<VertexShadowDepth_OutputDepth, true> >(VFType);
|
|
DomainShader = Material.GetShader<TShadowDepthDS<VertexShadowDepth_OutputDepth, true> >(VFType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bPositionOnlyVS)
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, false, true> >(VFType);
|
|
}
|
|
else
|
|
{
|
|
VertexShader = Material.GetShader<TShadowDepthVS<VertexShadowDepth_OutputDepth, false, false> >(VFType);
|
|
}
|
|
|
|
if (bInitializeTessellationShaders)
|
|
{
|
|
HullShader = Material.GetShader<TShadowDepthHS<VertexShadowDepth_OutputDepth, false> >(VFType);
|
|
DomainShader = Material.GetShader<TShadowDepthDS<VertexShadowDepth_OutputDepth, false> >(VFType);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pixel shaders
|
|
if (Material.WritesEveryPixel(true) && !bUsePerspectiveCorrectShadowDepths && !bRenderingReflectiveShadowMaps && VertexFactory->SupportsNullPixelShader())
|
|
{
|
|
// No pixel shader necessary.
|
|
PixelShader = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (bUsePerspectiveCorrectShadowDepths)
|
|
{
|
|
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)Material.GetShader<TShadowDepthPS<PixelShadowDepth_PerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType, false);
|
|
}
|
|
else if (bOnePassPointLightShadow)
|
|
{
|
|
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)Material.GetShader<TShadowDepthPS<PixelShadowDepth_OnePassPointLight, false> >(VFType, false);
|
|
}
|
|
else
|
|
{
|
|
PixelShader = (TShadowDepthBasePS<bRenderingReflectiveShadowMaps> *)Material.GetShader<TShadowDepthPS<PixelShadowDepth_NonPerspectiveCorrect, bRenderingReflectiveShadowMaps> >(VFType, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
FProjectedShadowInfo
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
static void CheckShadowDepthMaterials(const FMaterialRenderProxy* InRenderProxy, const FMaterial* InMaterial, bool bReflectiveShadowmap, ERHIFeatureLevel::Type InFeatureLevel)
|
|
{
|
|
const FMaterialRenderProxy* RenderProxy = InRenderProxy;
|
|
const FMaterial* Material = InMaterial;
|
|
OverrideWithDefaultMaterialForShadowDepth(RenderProxy, Material, bReflectiveShadowmap, InFeatureLevel);
|
|
check(RenderProxy == InRenderProxy);
|
|
check(Material == InMaterial);
|
|
}
|
|
|
|
void FProjectedShadowInfo::ClearDepth(FRHICommandList& RHICmdList, class FSceneRenderer* SceneRenderer, int32 NumColorTextures, FTextureRHIParamRef* ColorTextures, FTextureRHIParamRef DepthTexture, bool bPerformClear)
|
|
{
|
|
check(RHICmdList.IsInsideRenderPass());
|
|
|
|
uint32 ViewportMinX = X;
|
|
uint32 ViewportMinY = Y;
|
|
float ViewportMinZ = 0.0f;
|
|
uint32 ViewportMaxX = X + BorderSize * 2 + ResolutionX;
|
|
uint32 ViewportMaxY = Y + BorderSize * 2 + ResolutionY;
|
|
float ViewportMaxZ = 1.0f;
|
|
|
|
int32 NumClearColors;
|
|
bool bClearColor;
|
|
FLinearColor Colors[2];
|
|
|
|
// Translucent shadows use draw call clear
|
|
check(!bTranslucentShadow);
|
|
|
|
if (bReflectiveShadowmap)
|
|
{
|
|
// Clear color and depth targets
|
|
bClearColor = true;
|
|
Colors[0] = FLinearColor(0, 0, 1, 0);
|
|
Colors[1] = FLinearColor(0, 0, 0, 0);
|
|
|
|
NumClearColors = FMath::Min(2, NumColorTextures);
|
|
}
|
|
else
|
|
{
|
|
// Clear depth only.
|
|
bClearColor = false;
|
|
Colors[0] = FLinearColor::White;
|
|
NumClearColors = FMath::Min(1, NumColorTextures);
|
|
}
|
|
|
|
if (bPerformClear)
|
|
{
|
|
RHICmdList.SetViewport(
|
|
ViewportMinX,
|
|
ViewportMinY,
|
|
ViewportMinZ,
|
|
ViewportMaxX,
|
|
ViewportMaxY,
|
|
ViewportMaxZ
|
|
);
|
|
|
|
DrawClearQuadMRT(RHICmdList, bClearColor, NumClearColors, Colors, true, 1.0f, false, 0);
|
|
}
|
|
else
|
|
{
|
|
RHICmdList.BindClearMRTValues(bClearColor, true, false);
|
|
}
|
|
}
|
|
|
|
void FProjectedShadowInfo::SetStateForView(FRHICommandList& RHICmdList) const
|
|
{
|
|
check(bAllocated);
|
|
|
|
RHICmdList.SetViewport(
|
|
X + BorderSize,
|
|
Y + BorderSize,
|
|
0.0f,
|
|
X + BorderSize + ResolutionX,
|
|
Y + BorderSize + ResolutionY,
|
|
1.0f
|
|
);
|
|
}
|
|
|
|
void SetStateForShadowDepth(bool bReflectiveShadowmap, bool bOnePassPointLightShadow, FMeshPassProcessorRenderState& DrawRenderState)
|
|
{
|
|
if (bReflectiveShadowmap && !bOnePassPointLightShadow)
|
|
{
|
|
// Enable color writes to the reflective shadow map targets with opaque blending
|
|
DrawRenderState.SetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA>::GetRHI());
|
|
}
|
|
else
|
|
{
|
|
// Disable color writes
|
|
DrawRenderState.SetBlendState(TStaticBlendState<CW_NONE>::GetRHI());
|
|
}
|
|
|
|
DrawRenderState.SetDepthStencilState(TStaticDepthStencilState<true, CF_LessEqual>::GetRHI());
|
|
}
|
|
|
|
static TAutoConsoleVariable<int32> CVarParallelShadows(
|
|
TEXT("r.ParallelShadows"),
|
|
1,
|
|
TEXT("Toggles parallel shadow rendering. Parallel rendering must be enabled for this to have an effect."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
static TAutoConsoleVariable<int32> CVarParallelShadowsNonWholeScene(
|
|
TEXT("r.ParallelShadowsNonWholeScene"),
|
|
0,
|
|
TEXT("Toggles parallel shadow rendering for non whole-scene shadows. r.ParallelShadows must be enabled for this to have an effect."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
|
|
static TAutoConsoleVariable<int32> CVarRHICmdShadowDeferredContexts(
|
|
TEXT("r.RHICmdShadowDeferredContexts"),
|
|
1,
|
|
TEXT("True to use deferred contexts to parallelize shadow command list execution."));
|
|
|
|
static TAutoConsoleVariable<int32> CVarRHICmdFlushRenderThreadTasksShadowPass(
|
|
TEXT("r.RHICmdFlushRenderThreadTasksShadowPass"),
|
|
0,
|
|
TEXT("Wait for completion of parallel render thread tasks at the end of each shadow pass. A more granular version of r.RHICmdFlushRenderThreadTasks. If either r.RHICmdFlushRenderThreadTasks or r.RHICmdFlushRenderThreadTasksShadowPass is > 0 we will flush."));
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("Shadow"), STAT_CLP_Shadow, STATGROUP_ParallelCommandListMarkers);
|
|
|
|
class FShadowParallelCommandListSet : public FParallelCommandListSet
|
|
{
|
|
FProjectedShadowInfo& ProjectedShadowInfo;
|
|
FBeginShadowRenderPassFunction BeginShadowRenderPass;
|
|
EShadowDepthRenderMode RenderMode;
|
|
|
|
public:
|
|
FShadowParallelCommandListSet(
|
|
const FViewInfo& InView,
|
|
const FSceneRenderer* InSceneRenderer,
|
|
FRHICommandListImmediate& InParentCmdList,
|
|
bool bInParallelExecute,
|
|
bool bInCreateSceneContext,
|
|
const FMeshPassProcessorRenderState& InDrawRenderState,
|
|
FProjectedShadowInfo& InProjectedShadowInfo,
|
|
FBeginShadowRenderPassFunction InBeginShadowRenderPass)
|
|
: FParallelCommandListSet(GET_STATID(STAT_CLP_Shadow), InView, InSceneRenderer, InParentCmdList, bInParallelExecute, bInCreateSceneContext, InDrawRenderState)
|
|
, ProjectedShadowInfo(InProjectedShadowInfo)
|
|
, BeginShadowRenderPass(InBeginShadowRenderPass)
|
|
{
|
|
bBalanceCommands = false;
|
|
}
|
|
|
|
virtual ~FShadowParallelCommandListSet()
|
|
{
|
|
Dispatch();
|
|
}
|
|
|
|
virtual void SetStateOnCommandList(FRHICommandList& CmdList) override
|
|
{
|
|
FParallelCommandListSet::SetStateOnCommandList(CmdList);
|
|
BeginShadowRenderPass(CmdList, false);
|
|
ProjectedShadowInfo.SetStateForView(CmdList);
|
|
}
|
|
};
|
|
|
|
class FCopyShadowMapsCubeGS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopyShadowMapsCubeGS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return RHISupportsGeometryShaders(Parameters.Platform) && IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FCopyShadowMapsCubeGS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FGlobalShader(Initializer)
|
|
{
|
|
}
|
|
FCopyShadowMapsCubeGS() {}
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FCopyShadowMapsCubeGS, TEXT("/Engine/Private/CopyShadowMaps.usf"), TEXT("CopyCubeDepthGS"), SF_Geometry);
|
|
|
|
class FCopyShadowMapsCubePS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopyShadowMapsCubePS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FCopyShadowMapsCubePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FGlobalShader(Initializer)
|
|
{
|
|
ShadowDepthTexture.Bind(Initializer.ParameterMap, TEXT("ShadowDepthCubeTexture"));
|
|
ShadowDepthSampler.Bind(Initializer.ParameterMap, TEXT("ShadowDepthSampler"));
|
|
}
|
|
FCopyShadowMapsCubePS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, IPooledRenderTarget* SourceShadowMap)
|
|
{
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetPixelShader(), View.ViewUniformBuffer);
|
|
|
|
SetTextureParameter(RHICmdList, GetPixelShader(), ShadowDepthTexture, ShadowDepthSampler, TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(), SourceShadowMap->GetRenderTargetItem().ShaderResourceTexture);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ShadowDepthTexture;
|
|
Ar << ShadowDepthSampler;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
FShaderResourceParameter ShadowDepthTexture;
|
|
FShaderResourceParameter ShadowDepthSampler;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FCopyShadowMapsCubePS, TEXT("/Engine/Private/CopyShadowMaps.usf"), TEXT("CopyCubeDepthPS"), SF_Pixel);
|
|
|
|
/** */
|
|
class FCopyShadowMaps2DPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopyShadowMaps2DPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FCopyShadowMaps2DPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FGlobalShader(Initializer)
|
|
{
|
|
ShadowDepthTexture.Bind(Initializer.ParameterMap, TEXT("ShadowDepthTexture"));
|
|
ShadowDepthSampler.Bind(Initializer.ParameterMap, TEXT("ShadowDepthSampler"));
|
|
}
|
|
FCopyShadowMaps2DPS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, IPooledRenderTarget* SourceShadowMap)
|
|
{
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, GetPixelShader(), View.ViewUniformBuffer);
|
|
|
|
SetTextureParameter(RHICmdList, GetPixelShader(), ShadowDepthTexture, ShadowDepthSampler, TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(), SourceShadowMap->GetRenderTargetItem().ShaderResourceTexture);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << ShadowDepthTexture;
|
|
Ar << ShadowDepthSampler;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
FShaderResourceParameter ShadowDepthTexture;
|
|
FShaderResourceParameter ShadowDepthSampler;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FCopyShadowMaps2DPS, TEXT("/Engine/Private/CopyShadowMaps.usf"), TEXT("Copy2DDepthPS"), SF_Pixel);
|
|
|
|
void FProjectedShadowInfo::CopyCachedShadowMap(FRHICommandList& RHICmdList, const FMeshPassProcessorRenderState& DrawRenderState, FSceneRenderer* SceneRenderer, const FViewInfo& View)
|
|
{
|
|
check(CacheMode == SDCM_MovablePrimitivesOnly);
|
|
const FCachedShadowMapData& CachedShadowMapData = SceneRenderer->Scene->CachedShadowMaps.FindChecked(GetLightSceneInfo().Id);
|
|
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
DrawRenderState.ApplyToPSO(GraphicsPSOInit);
|
|
uint32 StencilRef = DrawRenderState.GetStencilRef();
|
|
|
|
if (CachedShadowMapData.bCachedShadowMapHasPrimitives && CachedShadowMapData.ShadowMap.IsValid())
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, CopyCachedShadowMap);
|
|
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
// No depth tests, so we can replace the clear
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<true, CF_Always>::GetRHI();
|
|
|
|
extern TGlobalResource<FFilterVertexDeclaration> GFilterVertexDeclaration;
|
|
|
|
if (bOnePassPointLightShadow)
|
|
{
|
|
if (RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[SceneRenderer->FeatureLevel]))
|
|
{
|
|
// Set shaders and texture
|
|
TShaderMapRef<TScreenVSForGS<false>> ScreenVertexShader(View.ShaderMap);
|
|
TShaderMapRef<FCopyShadowMapsCubeGS> GeometryShader(View.ShaderMap);
|
|
TShaderMapRef<FCopyShadowMapsCubePS> PixelShader(View.ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
|
|
#if PLATFORM_SUPPORTS_GEOMETRY_SHADERS
|
|
GraphicsPSOInit.BoundShaderState.GeometryShaderRHI = GETSAFERHISHADER_GEOMETRY(*GeometryShader);
|
|
#endif
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
RHICmdList.SetStencilRef(StencilRef);
|
|
|
|
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
0, 0,
|
|
ResolutionX, ResolutionY,
|
|
BorderSize, BorderSize,
|
|
ResolutionX, ResolutionY,
|
|
FIntPoint(ResolutionX, ResolutionY),
|
|
CachedShadowMapData.ShadowMap.GetSize(),
|
|
*ScreenVertexShader,
|
|
EDRF_Default);
|
|
}
|
|
else
|
|
{
|
|
check(RHISupportsVertexShaderLayer(GShaderPlatformForFeatureLevel[SceneRenderer->FeatureLevel]));
|
|
|
|
// Set shaders and texture
|
|
TShaderMapRef<TScreenVSForGS<true>> ScreenVertexShader(View.ShaderMap);
|
|
TShaderMapRef<FCopyShadowMapsCubePS> PixelShader(View.ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
RHICmdList.SetStencilRef(StencilRef);
|
|
|
|
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
0, 0,
|
|
ResolutionX, ResolutionY,
|
|
BorderSize, BorderSize,
|
|
ResolutionX, ResolutionY,
|
|
FIntPoint(ResolutionX, ResolutionY),
|
|
CachedShadowMapData.ShadowMap.GetSize(),
|
|
*ScreenVertexShader,
|
|
EDRF_Default,
|
|
6);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set shaders and texture
|
|
TShaderMapRef<FScreenVS> ScreenVertexShader(View.ShaderMap);
|
|
TShaderMapRef<FCopyShadowMaps2DPS> PixelShader(View.ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = GETSAFERHISHADER_VERTEX(*ScreenVertexShader);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = GETSAFERHISHADER_PIXEL(*PixelShader);
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
RHICmdList.SetStencilRef(StencilRef);
|
|
|
|
PixelShader->SetParameters(RHICmdList, View, CachedShadowMapData.ShadowMap.DepthTarget.GetReference());
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
0, 0,
|
|
ResolutionX, ResolutionY,
|
|
BorderSize, BorderSize,
|
|
ResolutionX, ResolutionY,
|
|
FIntPoint(ResolutionX, ResolutionY),
|
|
CachedShadowMapData.ShadowMap.GetSize(),
|
|
*ScreenVertexShader,
|
|
EDRF_Default);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FProjectedShadowInfo::RenderDepthInner(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch)
|
|
{
|
|
const ERHIFeatureLevel::Type FeatureLevel = ShadowDepthView->FeatureLevel;
|
|
FUniformBufferRHIParamRef PassUniformBuffer = nullptr;
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Deferred)
|
|
{
|
|
FShadowDepthPassUniformParameters ShadowDepthPassParameters;
|
|
SetupShadowDepthPassUniformBuffer(this, RHICmdList, *ShadowDepthView, ShadowDepthPassParameters);
|
|
|
|
if (IsWholeSceneDirectionalShadow() && !bReflectiveShadowmap)
|
|
{
|
|
check(GetShadowDepthType() == CSMShadowDepthType);
|
|
SceneRenderer->Scene->UniformBuffers.CSMShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
|
|
}
|
|
|
|
ShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
|
|
PassUniformBuffer = ShadowDepthPassUniformBuffer;
|
|
|
|
UploadDynamicPrimitiveShaderDataForView(RHICmdList, *SceneRenderer->Scene, *ShadowDepthView);
|
|
}
|
|
|
|
const bool bIsWholeSceneDirectionalShadow = IsWholeSceneDirectionalShadow();
|
|
|
|
if (bIsWholeSceneDirectionalShadow)
|
|
{
|
|
// CSM shadow depth cached mesh draw commands are all referencing the same view uniform buffer. We need to update it before rendering each cascade.
|
|
ShadowDepthView->ViewUniformBuffer.UpdateUniformBufferImmediate(*ShadowDepthView->CachedViewUniformShaderParameters);
|
|
}
|
|
|
|
if (FSceneInterface::GetShadingPath(FeatureLevel) == EShadingPath::Mobile)
|
|
{
|
|
FMobileShadowDepthPassUniformParameters ShadowDepthPassParameters;
|
|
SetupShadowDepthPassUniformBuffer(this, RHICmdList, *ShadowDepthView, ShadowDepthPassParameters);
|
|
SceneRenderer->Scene->UniformBuffers.MobileCSMShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
|
|
MobileShadowDepthPassUniformBuffer.UpdateUniformBufferImmediate(ShadowDepthPassParameters);
|
|
PassUniformBuffer = SceneRenderer->Scene->UniformBuffers.MobileCSMShadowDepthPassUniformBuffer;
|
|
}
|
|
|
|
FMeshPassProcessorRenderState DrawRenderState(*ShadowDepthView, PassUniformBuffer);
|
|
SetStateForShadowDepth(bReflectiveShadowmap, bOnePassPointLightShadow, DrawRenderState);
|
|
SetStateForView(RHICmdList);
|
|
|
|
if (CacheMode == SDCM_MovablePrimitivesOnly)
|
|
{
|
|
// In parallel mode we will not have a renderpass active at this point.
|
|
if (bDoParallelDispatch)
|
|
{
|
|
BeginShadowRenderPass(RHICmdList, false);
|
|
}
|
|
|
|
// Copy in depths of static primitives before we render movable primitives
|
|
CopyCachedShadowMap(RHICmdList, DrawRenderState, SceneRenderer, *ShadowDepthView);
|
|
|
|
if (bDoParallelDispatch)
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
}
|
|
|
|
if (bDoParallelDispatch)
|
|
{
|
|
check(IsInRenderingThread());
|
|
// Parallel encoding requires its own renderpass.
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
|
|
// parallel version
|
|
bool bFlush = CVarRHICmdFlushRenderThreadTasksShadowPass.GetValueOnRenderThread() > 0
|
|
|| CVarRHICmdFlushRenderThreadTasks.GetValueOnRenderThread() > 0;
|
|
FScopedCommandListWaitForTasks Flusher(bFlush);
|
|
|
|
// Dispatch commands
|
|
{
|
|
FShadowParallelCommandListSet ParallelCommandListSet(*ShadowDepthView, SceneRenderer, RHICmdList, CVarRHICmdShadowDeferredContexts.GetValueOnRenderThread() > 0, !bFlush, DrawRenderState, *this, BeginShadowRenderPass);
|
|
|
|
ShadowDepthPass.DispatchDraw(&ParallelCommandListSet, RHICmdList);
|
|
}
|
|
|
|
// Renderpass must be closed once we get here.
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
}
|
|
else
|
|
{
|
|
// We must have already opened the renderpass by the time we get here.
|
|
check(RHICmdList.IsInsideRenderPass());
|
|
|
|
ShadowDepthPass.DispatchDraw(nullptr, RHICmdList);
|
|
|
|
// Renderpass must still be open when we reach here
|
|
check(RHICmdList.IsInsideRenderPass());
|
|
}
|
|
}
|
|
|
|
void FProjectedShadowInfo::ModifyViewForShadow(FRHICommandList& RHICmdList, FViewInfo* FoundView) const
|
|
{
|
|
FIntRect OriginalViewRect = FoundView->ViewRect;
|
|
FoundView->ViewRect.Min.X = 0;
|
|
FoundView->ViewRect.Min.Y = 0;
|
|
FoundView->ViewRect.Max.X = ResolutionX;
|
|
FoundView->ViewRect.Max.Y = ResolutionY;
|
|
|
|
FoundView->ViewMatrices.HackRemoveTemporalAAProjectionJitter();
|
|
|
|
// Don't do material texture mip biasing in shadow maps.
|
|
FoundView->MaterialTextureMipBias = 0;
|
|
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
FoundView->CachedViewUniformShaderParameters = MakeUnique<FViewUniformShaderParameters>();
|
|
|
|
// Override the view matrix so that billboarding primitives will be aligned to the light
|
|
FoundView->ViewMatrices.HackOverrideViewMatrixForShadows(ShadowViewMatrix);
|
|
FBox VolumeBounds[TVC_MAX];
|
|
FoundView->SetupUniformBufferParameters(
|
|
SceneContext,
|
|
VolumeBounds,
|
|
TVC_MAX,
|
|
*FoundView->CachedViewUniformShaderParameters);
|
|
|
|
if (IsWholeSceneDirectionalShadow())
|
|
{
|
|
FScene* Scene = (FScene*)FoundView->Family->Scene;
|
|
FoundView->ViewUniformBuffer = Scene->UniformBuffers.CSMShadowDepthViewUniformBuffer;
|
|
}
|
|
else
|
|
{
|
|
FoundView->ViewUniformBuffer = TUniformBufferRef<FViewUniformShaderParameters>::CreateUniformBufferImmediate(*FoundView->CachedViewUniformShaderParameters, UniformBuffer_SingleFrame);
|
|
}
|
|
|
|
// we are going to set this back now because we only want the correct view rect for the uniform buffer. For LOD calculations, we want the rendering viewrect and proj matrix.
|
|
FoundView->ViewRect = OriginalViewRect;
|
|
|
|
extern int32 GPreshadowsForceLowestLOD;
|
|
|
|
if (bPreShadow && GPreshadowsForceLowestLOD)
|
|
{
|
|
FoundView->DrawDynamicFlags = EDrawDynamicFlags::ForceLowestLOD;
|
|
}
|
|
}
|
|
|
|
FViewInfo* FProjectedShadowInfo::FindViewForShadow(FSceneRenderer* SceneRenderer) const
|
|
{
|
|
// Choose an arbitrary view where this shadow's subject is relevant.
|
|
FViewInfo* FoundView = NULL;
|
|
for (int32 ViewIndex = 0; ViewIndex < SceneRenderer->Views.Num(); ViewIndex++)
|
|
{
|
|
FViewInfo* CheckView = &SceneRenderer->Views[ViewIndex];
|
|
const FVisibleLightViewInfo& VisibleLightViewInfo = CheckView->VisibleLightInfos[LightSceneInfo->Id];
|
|
FPrimitiveViewRelevance ViewRel = VisibleLightViewInfo.ProjectedShadowViewRelevanceMap[ShadowId];
|
|
if (ViewRel.bShadowRelevance)
|
|
{
|
|
FoundView = CheckView;
|
|
break;
|
|
}
|
|
}
|
|
check(FoundView);
|
|
return FoundView;
|
|
}
|
|
|
|
void FProjectedShadowInfo::RenderDepth(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer, FBeginShadowRenderPassFunction BeginShadowRenderPass, bool bDoParallelDispatch)
|
|
{
|
|
#if WANTS_DRAW_MESH_EVENTS
|
|
FString EventName;
|
|
|
|
if (GetEmitDrawEvents())
|
|
{
|
|
GetShadowTypeNameForDrawEvent(EventName);
|
|
EventName += FString(TEXT(" ")) + FString::FromInt(ResolutionX) + TEXT("x") + FString::FromInt(ResolutionY);
|
|
}
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepthActor, *EventName);
|
|
#endif
|
|
|
|
CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderWholeSceneShadowDepthsTime, bWholeSceneShadow);
|
|
CONDITIONAL_SCOPE_CYCLE_COUNTER(STAT_RenderPerObjectShadowDepthsTime, !bWholeSceneShadow);
|
|
QUICK_SCOPE_CYCLE_COUNTER(STAT_RenderShadowDepth);
|
|
|
|
RenderDepthInner(RHICmdList, SceneRenderer, BeginShadowRenderPass, bDoParallelDispatch);
|
|
}
|
|
|
|
void FProjectedShadowInfo::SetupShadowDepthView(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer)
|
|
{
|
|
FViewInfo* FoundView = FindViewForShadow(SceneRenderer);
|
|
check(FoundView && IsInRenderingThread());
|
|
FViewInfo* DepthPassView = FoundView->CreateSnapshot();
|
|
ModifyViewForShadow(RHICmdList, DepthPassView);
|
|
ShadowDepthView = DepthPassView;
|
|
}
|
|
|
|
void FProjectedShadowInfo::GetShadowTypeNameForDrawEvent(FString& TypeName) const
|
|
{
|
|
const FName ParentName = ParentSceneInfo ? ParentSceneInfo->Proxy->GetOwnerName() : NAME_None;
|
|
|
|
if (bWholeSceneShadow)
|
|
{
|
|
if (CascadeSettings.ShadowSplitIndex >= 0)
|
|
{
|
|
TypeName = FString(TEXT("WholeScene split")) + FString::FromInt(CascadeSettings.ShadowSplitIndex);
|
|
}
|
|
else
|
|
{
|
|
if (CacheMode == SDCM_MovablePrimitivesOnly)
|
|
{
|
|
TypeName = FString(TEXT("WholeScene MovablePrimitives"));
|
|
}
|
|
else if (CacheMode == SDCM_StaticPrimitivesOnly)
|
|
{
|
|
TypeName = FString(TEXT("WholeScene StaticPrimitives"));
|
|
}
|
|
else
|
|
{
|
|
TypeName = FString(TEXT("WholeScene"));
|
|
}
|
|
}
|
|
}
|
|
else if (bPreShadow)
|
|
{
|
|
TypeName = FString(TEXT("PreShadow ")) + ParentName.ToString();
|
|
}
|
|
else
|
|
{
|
|
TypeName = FString(TEXT("PerObject ")) + ParentName.ToString();
|
|
}
|
|
}
|
|
|
|
void FSceneRenderer::RenderShadowDepthMapAtlases(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
bool bCanUseParallelDispatch = RHICmdList.IsImmediate() && // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
|
|
GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread();
|
|
|
|
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.ShadowMapAtlases.Num(); AtlasIndex++)
|
|
{
|
|
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.ShadowMapAtlases[AtlasIndex];
|
|
FSceneRenderTargetItem& RenderTarget = ShadowMapAtlas.RenderTargets.DepthTarget->GetRenderTargetItem();
|
|
FIntPoint AtlasSize = ShadowMapAtlas.RenderTargets.DepthTarget->GetDesc().Extent;
|
|
|
|
GVisualizeTexture.SetCheckPoint(RHICmdList, ShadowMapAtlas.RenderTargets.DepthTarget.GetReference());
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("Atlas%u %ux%u"), AtlasIndex, AtlasSize.X, AtlasSize.Y);
|
|
|
|
auto BeginShadowRenderPass = [this, &RenderTarget, &SceneContext](FRHICommandList& InRHICmdList, bool bPerformClear)
|
|
{
|
|
check(RenderTarget.TargetableTexture->GetDepthClearValue() == 1.0f);
|
|
|
|
ERenderTargetLoadAction DepthLoadAction = bPerformClear ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad;
|
|
|
|
FRHIRenderPassInfo RPInfo(RenderTarget.TargetableTexture, MakeDepthStencilTargetActions(MakeRenderTargetActions(DepthLoadAction, ERenderTargetStoreAction::EStore), ERenderTargetActions::Load_Store), nullptr, FExclusiveDepthStencil::DepthWrite_StencilWrite);
|
|
|
|
if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
|
|
{
|
|
RPInfo.ColorRenderTargets[0].Action = ERenderTargetActions::DontLoad_DontStore;
|
|
RPInfo.ColorRenderTargets[0].RenderTarget = SceneContext.GetOptionalShadowDepthColorSurface(InRHICmdList, RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetTexture2D()->GetSizeX(), RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetTexture2D()->GetSizeY());
|
|
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, RPInfo.ColorRenderTargets[0].RenderTarget);
|
|
}
|
|
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, RPInfo.DepthStencilRenderTarget.DepthStencilTarget);
|
|
InRHICmdList.BeginRenderPass(RPInfo, TEXT("ShadowMapAtlases"));
|
|
|
|
if (!bPerformClear)
|
|
{
|
|
InRHICmdList.BindClearMRTValues(false, true, false);
|
|
}
|
|
};
|
|
|
|
TArray<FProjectedShadowInfo*, SceneRenderingAllocator> ParallelShadowPasses;
|
|
TArray<FProjectedShadowInfo*, SceneRenderingAllocator> SerialShadowPasses;
|
|
|
|
// Gather our passes here to minimize switching renderpasses
|
|
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
|
|
|
|
const bool bDoParallelDispatch = bCanUseParallelDispatch &&
|
|
(ProjectedShadowInfo->IsWholeSceneDirectionalShadow() || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread());
|
|
|
|
if (bDoParallelDispatch)
|
|
{
|
|
ParallelShadowPasses.Add(ProjectedShadowInfo);
|
|
}
|
|
else
|
|
{
|
|
SerialShadowPasses.Add(ProjectedShadowInfo);
|
|
}
|
|
}
|
|
|
|
FLightSceneProxy* CurrentLightForDrawEvent = NULL;
|
|
|
|
#if WANTS_DRAW_MESH_EVENTS
|
|
TDrawEvent<FRHICommandList> LightEvent;
|
|
#endif
|
|
|
|
if (ParallelShadowPasses.Num() > 0)
|
|
{
|
|
{
|
|
// Clear before going wide.
|
|
SCOPED_DRAW_EVENT(RHICmdList, SetShadowRTsAndClear);
|
|
BeginShadowRenderPass(RHICmdList, true);
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < ParallelShadowPasses.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = ParallelShadowPasses[ShadowIndex];
|
|
|
|
if (!CurrentLightForDrawEvent || ProjectedShadowInfo->GetLightSceneInfo().Proxy != CurrentLightForDrawEvent)
|
|
{
|
|
if (CurrentLightForDrawEvent)
|
|
{
|
|
STOP_DRAW_EVENT(LightEvent);
|
|
}
|
|
|
|
CurrentLightForDrawEvent = ProjectedShadowInfo->GetLightSceneInfo().Proxy;
|
|
FString LightNameWithLevel;
|
|
GetLightNameForDrawEvent(CurrentLightForDrawEvent, LightNameWithLevel);
|
|
|
|
BEGIN_DRAW_EVENTF(
|
|
RHICmdList,
|
|
LightNameEvent,
|
|
LightEvent,
|
|
*LightNameWithLevel);
|
|
}
|
|
|
|
ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, true);
|
|
}
|
|
}
|
|
|
|
if (CurrentLightForDrawEvent)
|
|
{
|
|
STOP_DRAW_EVENT(LightEvent);
|
|
}
|
|
|
|
CurrentLightForDrawEvent = nullptr;
|
|
|
|
if (SerialShadowPasses.Num() > 0)
|
|
{
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, SetShadowRTsAndClear);
|
|
BeginShadowRenderPass(RHICmdList, true);
|
|
}
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < SerialShadowPasses.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = SerialShadowPasses[ShadowIndex];
|
|
|
|
if (!CurrentLightForDrawEvent || ProjectedShadowInfo->GetLightSceneInfo().Proxy != CurrentLightForDrawEvent)
|
|
{
|
|
if (CurrentLightForDrawEvent)
|
|
{
|
|
STOP_DRAW_EVENT(LightEvent);
|
|
}
|
|
|
|
CurrentLightForDrawEvent = ProjectedShadowInfo->GetLightSceneInfo().Proxy;
|
|
FString LightNameWithLevel;
|
|
GetLightNameForDrawEvent(CurrentLightForDrawEvent, LightNameWithLevel);
|
|
|
|
BEGIN_DRAW_EVENTF(
|
|
RHICmdList,
|
|
LightNameEvent,
|
|
LightEvent,
|
|
*LightNameWithLevel);
|
|
}
|
|
|
|
ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, false);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
if (CurrentLightForDrawEvent)
|
|
{
|
|
STOP_DRAW_EVENT(LightEvent);
|
|
CurrentLightForDrawEvent = NULL;
|
|
}
|
|
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
|
|
}
|
|
}
|
|
|
|
void FSceneRenderer::RenderShadowDepthMaps(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
check(RHICmdList.IsOutsideRenderPass());
|
|
|
|
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(RenderShadows);
|
|
SCOPED_NAMED_EVENT(FSceneRenderer_RenderShadowDepthMaps, FColor::Emerald);
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, ShadowDepths);
|
|
SCOPED_GPU_STAT(RHICmdList, ShadowDepths);
|
|
|
|
FSceneRenderer::RenderShadowDepthMapAtlases(RHICmdList);
|
|
|
|
checkSlow(RHICmdList.IsOutsideRenderPass());
|
|
|
|
for (int32 CubemapIndex = 0; CubemapIndex < SortedShadowsForShadowDepthPass.ShadowMapCubemaps.Num(); CubemapIndex++)
|
|
{
|
|
const FSortedShadowMapAtlas& ShadowMap = SortedShadowsForShadowDepthPass.ShadowMapCubemaps[CubemapIndex];
|
|
FSceneRenderTargetItem& RenderTarget = ShadowMap.RenderTargets.DepthTarget->GetRenderTargetItem();
|
|
FIntPoint TargetSize = ShadowMap.RenderTargets.DepthTarget->GetDesc().Extent;
|
|
|
|
check(ShadowMap.Shadows.Num() == 1);
|
|
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMap.Shadows[0];
|
|
|
|
const bool bDoParallelDispatch = RHICmdList.IsImmediate() && // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
|
|
GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread() &&
|
|
(ProjectedShadowInfo->IsWholeSceneDirectionalShadow() || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread());
|
|
|
|
GVisualizeTexture.SetCheckPoint(RHICmdList, ShadowMap.RenderTargets.DepthTarget.GetReference());
|
|
|
|
FString LightNameWithLevel;
|
|
GetLightNameForDrawEvent(ProjectedShadowInfo->GetLightSceneInfo().Proxy, LightNameWithLevel);
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("Cubemap %s %u^2"), *LightNameWithLevel, TargetSize.X, TargetSize.Y);
|
|
|
|
auto BeginShadowRenderPass = [this, &RenderTarget, &SceneContext](FRHICommandList& InRHICmdList, bool bPerformClear)
|
|
{
|
|
FTextureRHIParamRef DepthTarget = RenderTarget.TargetableTexture;
|
|
ERenderTargetLoadAction DepthLoadAction = bPerformClear ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad;
|
|
|
|
check(DepthTarget->GetDepthClearValue() == 1.0f);
|
|
FRHIRenderPassInfo RPInfo(DepthTarget, MakeDepthStencilTargetActions(MakeRenderTargetActions(DepthLoadAction, ERenderTargetStoreAction::EStore), ERenderTargetActions::Load_Store), nullptr, FExclusiveDepthStencil::DepthWrite_StencilWrite);
|
|
|
|
if (!GSupportsDepthRenderTargetWithoutColorRenderTarget)
|
|
{
|
|
RPInfo.ColorRenderTargets[0].Action = ERenderTargetActions::DontLoad_DontStore;
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = -1;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = 0;
|
|
RPInfo.ColorRenderTargets[0].RenderTarget = SceneContext.GetOptionalShadowDepthColorSurface(InRHICmdList, DepthTarget->GetTexture2D()->GetSizeX(), DepthTarget->GetTexture2D()->GetSizeY());
|
|
|
|
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, RPInfo.ColorRenderTargets[0].RenderTarget);
|
|
}
|
|
InRHICmdList.TransitionResource(EResourceTransitionAccess::EWritable, DepthTarget);
|
|
InRHICmdList.BeginRenderPass(RPInfo, TEXT("ShadowDepthCubeMaps"));
|
|
};
|
|
|
|
{
|
|
bool bDoClear = true;
|
|
|
|
if (ProjectedShadowInfo->CacheMode == SDCM_MovablePrimitivesOnly
|
|
&& Scene->CachedShadowMaps.FindChecked(ProjectedShadowInfo->GetLightSceneInfo().Id).bCachedShadowMapHasPrimitives)
|
|
{
|
|
// Skip the clear when we'll copy from a cached shadowmap
|
|
bDoClear = false;
|
|
}
|
|
|
|
SCOPED_CONDITIONAL_DRAW_EVENT(RHICmdList, Clear, bDoClear);
|
|
BeginShadowRenderPass(RHICmdList, bDoClear);
|
|
}
|
|
|
|
if (bDoParallelDispatch)
|
|
{
|
|
// In parallel mode this first pass will just be the clear.
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, bDoParallelDispatch);
|
|
|
|
if (!bDoParallelDispatch)
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
|
|
}
|
|
|
|
checkSlow(RHICmdList.IsOutsideRenderPass());
|
|
|
|
if (SortedShadowsForShadowDepthPass.PreshadowCache.Shadows.Num() > 0)
|
|
{
|
|
FSceneRenderTargetItem& RenderTarget = SortedShadowsForShadowDepthPass.PreshadowCache.RenderTargets.DepthTarget->GetRenderTargetItem();
|
|
|
|
GVisualizeTexture.SetCheckPoint(RHICmdList, SortedShadowsForShadowDepthPass.PreshadowCache.RenderTargets.DepthTarget.GetReference());
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, PreshadowCache);
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < SortedShadowsForShadowDepthPass.PreshadowCache.Shadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = SortedShadowsForShadowDepthPass.PreshadowCache.Shadows[ShadowIndex];
|
|
|
|
if (!ProjectedShadowInfo->bDepthsCached)
|
|
{
|
|
const bool bDoParallelDispatch = RHICmdList.IsImmediate() && // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
|
|
GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread() &&
|
|
(ProjectedShadowInfo->IsWholeSceneDirectionalShadow() || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread());
|
|
|
|
auto BeginShadowRenderPass = [this, ProjectedShadowInfo](FRHICommandList& InRHICmdList, bool bPerformClear)
|
|
{
|
|
FTextureRHIParamRef PreShadowCacheDepthZ = Scene->PreShadowCacheDepthZ->GetRenderTargetItem().TargetableTexture.GetReference();
|
|
InRHICmdList.TransitionResources(EResourceTransitionAccess::EWritable, &PreShadowCacheDepthZ, 1);
|
|
|
|
FRHIRenderPassInfo RPInfo(PreShadowCacheDepthZ, EDepthStencilTargetActions::LoadDepthStencil_StoreDepthStencil, nullptr, FExclusiveDepthStencil::DepthWrite_StencilWrite);
|
|
|
|
// Must preserve existing contents as the clear will be scissored
|
|
InRHICmdList.BeginRenderPass(RPInfo, TEXT("ShadowDepthMaps"));
|
|
ProjectedShadowInfo->ClearDepth(InRHICmdList, this, 0, nullptr, PreShadowCacheDepthZ, bPerformClear);
|
|
};
|
|
|
|
BeginShadowRenderPass(RHICmdList, true);
|
|
|
|
if (bDoParallelDispatch)
|
|
{
|
|
// In parallel mode the first pass is just the clear.
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, bDoParallelDispatch);
|
|
|
|
if (!bDoParallelDispatch)
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
ProjectedShadowInfo->bDepthsCached = true;
|
|
}
|
|
}
|
|
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, RenderTarget.TargetableTexture);
|
|
}
|
|
|
|
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.TranslucencyShadowMapAtlases.Num(); AtlasIndex++)
|
|
{
|
|
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.TranslucencyShadowMapAtlases[AtlasIndex];
|
|
FIntPoint TargetSize = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetDesc().Extent;
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("TranslucencyAtlas%u %u^2"), AtlasIndex, TargetSize.X, TargetSize.Y);
|
|
|
|
FSceneRenderTargetItem ColorTarget0 = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetRenderTargetItem();
|
|
FSceneRenderTargetItem ColorTarget1 = ShadowMapAtlas.RenderTargets.ColorTargets[1]->GetRenderTargetItem();
|
|
|
|
FTextureRHIParamRef RenderTargetArray[2] =
|
|
{
|
|
ColorTarget0.TargetableTexture,
|
|
ColorTarget1.TargetableTexture
|
|
};
|
|
|
|
FRHIRenderPassInfo RPInfo(ARRAY_COUNT(RenderTargetArray), RenderTargetArray, ERenderTargetActions::Load_Store);
|
|
TransitionRenderPassTargets(RHICmdList, RPInfo);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("RenderTranslucencyDepths"));
|
|
{
|
|
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
|
|
ProjectedShadowInfo->RenderTranslucencyDepths(RHICmdList, this);
|
|
}
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, ColorTarget0.TargetableTexture);
|
|
RHICmdList.TransitionResource(EResourceTransitionAccess::EReadable, ColorTarget1.TargetableTexture);
|
|
}
|
|
|
|
// Get a copy of LpvWriteUniformBufferParams for parallel RSM draw-call submission
|
|
{
|
|
for (int32 ViewIdx = 0; ViewIdx < Views.Num(); ++ViewIdx)
|
|
{
|
|
FViewInfo& View = Views[ViewIdx];
|
|
FSceneViewState* ViewState = View.ViewState;
|
|
|
|
if (ViewState)
|
|
{
|
|
FLightPropagationVolume* Lpv = ViewState->GetLightPropagationVolume(FeatureLevel);
|
|
|
|
if (Lpv)
|
|
{
|
|
Lpv->SetRsmUniformBuffer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int32 AtlasIndex = 0; AtlasIndex < SortedShadowsForShadowDepthPass.RSMAtlases.Num(); AtlasIndex++)
|
|
{
|
|
checkSlow(RHICmdList.IsOutsideRenderPass());
|
|
|
|
const FSortedShadowMapAtlas& ShadowMapAtlas = SortedShadowsForShadowDepthPass.RSMAtlases[AtlasIndex];
|
|
FSceneRenderTargetItem ColorTarget0 = ShadowMapAtlas.RenderTargets.ColorTargets[0]->GetRenderTargetItem();
|
|
FSceneRenderTargetItem ColorTarget1 = ShadowMapAtlas.RenderTargets.ColorTargets[1]->GetRenderTargetItem();
|
|
FSceneRenderTargetItem DepthTarget = ShadowMapAtlas.RenderTargets.DepthTarget->GetRenderTargetItem();
|
|
FIntPoint TargetSize = ShadowMapAtlas.RenderTargets.DepthTarget->GetDesc().Extent;
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepths, TEXT("RSM%u %ux%u"), AtlasIndex, TargetSize.X, TargetSize.Y);
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < ShadowMapAtlas.Shadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* ProjectedShadowInfo = ShadowMapAtlas.Shadows[ShadowIndex];
|
|
|
|
const bool bDoParallelDispatch = RHICmdList.IsImmediate() && // translucent shadows are draw on the render thread, using a recursive cmdlist (which is not immediate)
|
|
GRHICommandList.UseParallelAlgorithms() && CVarParallelShadows.GetValueOnRenderThread() &&
|
|
(ProjectedShadowInfo->IsWholeSceneDirectionalShadow() || CVarParallelShadowsNonWholeScene.GetValueOnRenderThread());
|
|
|
|
FSceneViewState* ViewState = (FSceneViewState*)ProjectedShadowInfo->DependentView->State;
|
|
FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume(FeatureLevel);
|
|
|
|
auto BeginShadowRenderPass = [this, LightPropagationVolume, ProjectedShadowInfo, &ColorTarget0, &ColorTarget1, &DepthTarget](FRHICommandList& InRHICmdList, bool bPerformClear)
|
|
{
|
|
FTextureRHIParamRef RenderTargets[2];
|
|
RenderTargets[0] = ColorTarget0.TargetableTexture;
|
|
RenderTargets[1] = ColorTarget1.TargetableTexture;
|
|
|
|
// Hook up the geometry volume UAVs
|
|
FUnorderedAccessViewRHIParamRef Uavs[4];
|
|
Uavs[0] = LightPropagationVolume->GetGvListBufferUav();
|
|
Uavs[1] = LightPropagationVolume->GetGvListHeadBufferUav();
|
|
Uavs[2] = LightPropagationVolume->GetVplListBufferUav();
|
|
Uavs[3] = LightPropagationVolume->GetVplListHeadBufferUav();
|
|
|
|
FRHIRenderPassInfo RPInfo(ARRAY_COUNT(RenderTargets), RenderTargets, ERenderTargetActions::Load_Store);
|
|
RPInfo.DepthStencilRenderTarget.Action = EDepthStencilTargetActions::LoadDepthStencil_StoreDepthStencil;
|
|
RPInfo.DepthStencilRenderTarget.DepthStencilTarget = DepthTarget.TargetableTexture;
|
|
RPInfo.DepthStencilRenderTarget.ExclusiveDepthStencil = FExclusiveDepthStencil::DepthWrite_StencilWrite;
|
|
|
|
// Set starting UAV bind index
|
|
RPInfo.UAVIndex = ARRAY_COUNT(RenderTargets);
|
|
RPInfo.NumUAVs = ARRAY_COUNT(Uavs);
|
|
for (int32 Index = 0; Index < RPInfo.NumUAVs; Index++)
|
|
{
|
|
RPInfo.UAVs[Index] = Uavs[Index];
|
|
}
|
|
|
|
InRHICmdList.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToGfx, Uavs, ARRAY_COUNT(Uavs));
|
|
InRHICmdList.BeginRenderPass(RPInfo, TEXT("ShadowAtlas"));
|
|
|
|
ProjectedShadowInfo->ClearDepth(InRHICmdList, this, ARRAY_COUNT(RenderTargets), RenderTargets, DepthTarget.TargetableTexture, bPerformClear);
|
|
};
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, Clear);
|
|
BeginShadowRenderPass(RHICmdList, true);
|
|
}
|
|
|
|
// In parallel mode the first renderpass is just the clear.
|
|
if (bDoParallelDispatch)
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
|
|
ProjectedShadowInfo->RenderDepth(RHICmdList, this, BeginShadowRenderPass, bDoParallelDispatch);
|
|
|
|
if (!bDoParallelDispatch)
|
|
{
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
{
|
|
// Resolve the shadow depth z surface.
|
|
RHICmdList.CopyToResolveTarget(DepthTarget.TargetableTexture, DepthTarget.ShaderResourceTexture, FResolveParams());
|
|
RHICmdList.CopyToResolveTarget(ColorTarget0.TargetableTexture, ColorTarget0.ShaderResourceTexture, FResolveParams());
|
|
RHICmdList.CopyToResolveTarget(ColorTarget1.TargetableTexture, ColorTarget1.ShaderResourceTexture, FResolveParams());
|
|
|
|
FUnorderedAccessViewRHIParamRef UavsToReadable[2];
|
|
UavsToReadable[0] = LightPropagationVolume->GetGvListBufferUav();
|
|
UavsToReadable[1] = LightPropagationVolume->GetGvListHeadBufferUav();
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EGfxToGfx, UavsToReadable, ARRAY_COUNT(UavsToReadable));
|
|
}
|
|
checkSlow(RHICmdList.IsOutsideRenderPass());
|
|
}
|
|
}
|
|
|
|
checkSlow(RHICmdList.IsOutsideRenderPass());
|
|
}
|
|
|
|
template<bool bRenderReflectiveShadowMap>
|
|
void FShadowDepthPassMeshProcessor::Process(
|
|
const FMeshBatch& RESTRICT MeshBatch,
|
|
uint64 BatchElementMask,
|
|
int32 StaticMeshId,
|
|
const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy,
|
|
const FMaterialRenderProxy& RESTRICT MaterialRenderProxy,
|
|
const FMaterial& RESTRICT MaterialResource,
|
|
ERasterizerFillMode MeshFillMode,
|
|
ERasterizerCullMode MeshCullMode)
|
|
{
|
|
const FVertexFactory* VertexFactory = MeshBatch.VertexFactory;
|
|
|
|
TMeshProcessorShaders<
|
|
FShadowDepthVS,
|
|
FBaseHS,
|
|
FBaseDS,
|
|
TShadowDepthBasePS<bRenderReflectiveShadowMap>,
|
|
FOnePassPointShadowDepthGS> ShadowDepthPassShaders;
|
|
|
|
const bool bUsePositionOnlyVS = !bRenderReflectiveShadowMap
|
|
&& VertexFactory->SupportsPositionOnlyStream()
|
|
&& MaterialResource.WritesEveryPixel(true)
|
|
&& !MaterialResource.MaterialModifiesMeshPosition_RenderThread();
|
|
|
|
GetShadowDepthPassShaders<bRenderReflectiveShadowMap>(
|
|
MaterialResource,
|
|
VertexFactory,
|
|
FeatureLevel,
|
|
ShadowDepthType.bDirectionalLight,
|
|
ShadowDepthType.bOnePassPointLightShadow,
|
|
bUsePositionOnlyVS,
|
|
ShadowDepthPassShaders.VertexShader,
|
|
ShadowDepthPassShaders.HullShader,
|
|
ShadowDepthPassShaders.DomainShader,
|
|
ShadowDepthPassShaders.PixelShader,
|
|
ShadowDepthPassShaders.GeometryShader);
|
|
|
|
FShadowDepthShaderElementData ShaderElementData;
|
|
ShaderElementData.InitializeMeshMaterialData(ViewIfDynamicMeshCommand, PrimitiveSceneProxy, MeshBatch, StaticMeshId, false);
|
|
|
|
const FMeshDrawCommandSortKey SortKey = CalculateMeshStaticSortKey(ShadowDepthPassShaders.VertexShader, ShadowDepthPassShaders.PixelShader);
|
|
|
|
const uint32 InstanceFactor = !ShadowDepthType.bOnePassPointLightShadow || RHISupportsGeometryShaders(GShaderPlatformForFeatureLevel[FeatureLevel]) ? 1 : 6;
|
|
for (uint32 i = 0; i < InstanceFactor; i++)
|
|
{
|
|
ShaderElementData.LayerId = i;
|
|
|
|
BuildMeshDrawCommands(
|
|
MeshBatch,
|
|
BatchElementMask,
|
|
PrimitiveSceneProxy,
|
|
MaterialRenderProxy,
|
|
MaterialResource,
|
|
PassDrawRenderState,
|
|
ShadowDepthPassShaders,
|
|
MeshFillMode,
|
|
MeshCullMode,
|
|
SortKey,
|
|
bUsePositionOnlyVS ? EMeshPassFeatures::PositionOnly : EMeshPassFeatures::Default,
|
|
ShaderElementData);
|
|
}
|
|
}
|
|
|
|
void FShadowDepthPassMeshProcessor::AddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId)
|
|
{
|
|
if (MeshBatch.CastShadow)
|
|
{
|
|
// Determine the mesh's material and blend mode.
|
|
const FMaterialRenderProxy* FallbackMaterialRenderProxyPtr = nullptr;
|
|
const FMaterial& Material = MeshBatch.MaterialRenderProxy->GetMaterialWithFallback(FeatureLevel, FallbackMaterialRenderProxyPtr);
|
|
|
|
const FMaterialRenderProxy& MaterialRenderProxy = FallbackMaterialRenderProxyPtr ? *FallbackMaterialRenderProxyPtr : *MeshBatch.MaterialRenderProxy;
|
|
const EBlendMode BlendMode = Material.GetBlendMode();
|
|
const bool bReflectiveShadowmap = ShadowDepthType.bReflectiveShadowmap && !ShadowDepthType.bOnePassPointLightShadow;
|
|
const bool bShouldCastShadow = Material.ShouldCastDynamicShadows();
|
|
|
|
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(MeshBatch, Material);
|
|
|
|
ERasterizerCullMode FinalCullMode;
|
|
|
|
{
|
|
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(MeshBatch, Material);
|
|
|
|
const bool bTwoSided = Material.IsTwoSided() || PrimitiveSceneProxy->CastsShadowAsTwoSided();
|
|
// @TODO: only render directional light shadows as two sided, and only when blocking is enabled (required by geometry volume injection)
|
|
const bool bEffectivelyTwoSided = ShadowDepthType.bReflectiveShadowmap ? true : bTwoSided;
|
|
// Invert culling order when mobile HDR == false.
|
|
auto ShaderPlatform = GShaderPlatformForFeatureLevel[FeatureLevel];
|
|
static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR"));
|
|
check(MobileHDRCvar);
|
|
const bool bPlatformReversesCulling = (RHINeedsToSwitchVerticalAxis(ShaderPlatform) && MobileHDRCvar->GetValueOnAnyThread() == 0);
|
|
|
|
const bool bRenderSceneTwoSided = bEffectivelyTwoSided;
|
|
const bool bReverseCullMode = XOR(bPlatformReversesCulling, ShadowDepthType.bOnePassPointLightShadow);
|
|
|
|
FinalCullMode = bRenderSceneTwoSided ? CM_None : bReverseCullMode ? InverseCullMode(MeshCullMode) : MeshCullMode;
|
|
}
|
|
|
|
if ((bShouldCastShadow || (bReflectiveShadowmap && (Material.ShouldInjectEmissiveIntoLPV() || Material.ShouldBlockGI())))
|
|
&& ShouldIncludeDomainInMeshPass(Material.GetMaterialDomain()))
|
|
{
|
|
const FMaterialRenderProxy* EffectiveMaterialRenderProxy = &MaterialRenderProxy;
|
|
const FMaterial* EffectiveMaterial = &Material;
|
|
|
|
OverrideWithDefaultMaterialForShadowDepth(EffectiveMaterialRenderProxy, EffectiveMaterial, ShadowDepthType.bReflectiveShadowmap, FeatureLevel);
|
|
|
|
if (ShadowDepthType.bReflectiveShadowmap)
|
|
{
|
|
Process<true>(MeshBatch, BatchElementMask, StaticMeshId, PrimitiveSceneProxy, *EffectiveMaterialRenderProxy, *EffectiveMaterial, MeshFillMode, FinalCullMode);
|
|
}
|
|
else
|
|
{
|
|
Process<false>(MeshBatch, BatchElementMask, StaticMeshId, PrimitiveSceneProxy, *EffectiveMaterialRenderProxy, *EffectiveMaterial, MeshFillMode, FinalCullMode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FShadowDepthPassMeshProcessor::FShadowDepthPassMeshProcessor(
|
|
const FScene* Scene,
|
|
const FSceneView* InViewIfDynamicMeshCommand,
|
|
const TUniformBufferRef<FViewUniformShaderParameters>& InViewUniformBuffer,
|
|
FUniformBufferRHIParamRef InPassUniformBuffer,
|
|
FShadowDepthType InShadowDepthType,
|
|
FMeshPassDrawListContext* InDrawListContext)
|
|
: FMeshPassProcessor(Scene, Scene->GetFeatureLevel(), InViewIfDynamicMeshCommand, InDrawListContext)
|
|
, PassDrawRenderState(FMeshPassProcessorRenderState(InViewUniformBuffer, InPassUniformBuffer))
|
|
, ShadowDepthType(InShadowDepthType)
|
|
{
|
|
SetStateForShadowDepth(ShadowDepthType.bReflectiveShadowmap, ShadowDepthType.bOnePassPointLightShadow, PassDrawRenderState);
|
|
}
|
|
|
|
FShadowDepthType CSMShadowDepthType(true, false, false);
|
|
|
|
FMeshPassProcessor* CreateCSMShadowDepthPassProcessor(const FScene* Scene, const FSceneView* InViewIfDynamicMeshCommand, FMeshPassDrawListContext* InDrawListContext)
|
|
{
|
|
FUniformBufferRHIParamRef PassUniformBuffer = nullptr;
|
|
|
|
EShadingPath ShadingPath = Scene->GetShadingPath();
|
|
if (ShadingPath == EShadingPath::Mobile)
|
|
{
|
|
PassUniformBuffer = Scene->UniformBuffers.MobileCSMShadowDepthPassUniformBuffer;
|
|
}
|
|
else //deferred
|
|
{
|
|
PassUniformBuffer = Scene->UniformBuffers.CSMShadowDepthPassUniformBuffer;
|
|
}
|
|
|
|
return new(FMemStack::Get()) FShadowDepthPassMeshProcessor(
|
|
Scene,
|
|
InViewIfDynamicMeshCommand,
|
|
Scene->UniformBuffers.CSMShadowDepthViewUniformBuffer,
|
|
PassUniformBuffer,
|
|
CSMShadowDepthType,
|
|
InDrawListContext);
|
|
}
|
|
|
|
FRegisterPassProcessorCreateFunction RegisterCSMShadowDepthPass(&CreateCSMShadowDepthPassProcessor, EShadingPath::Deferred, EMeshPass::CSMShadowDepth, EMeshPassFlags::CachedMeshCommands);
|
|
FRegisterPassProcessorCreateFunction RegisterMobileCSMShadowDepthPass(&CreateCSMShadowDepthPassProcessor, EShadingPath::Mobile, EMeshPass::CSMShadowDepth, EMeshPassFlags::CachedMeshCommands);
|