1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
4 #include <CryMath/Range.h>
6 #include "HeightMapAO.h"
7 #include "D3DPostProcess.h"
9 #include "Common/Include_HLSL_CPP_Shared.h"
10 #include "Common/GraphicsPipelineStateSet.h"
11 #include "Common/TypedConstantBuffer.h"
12 #include "Common/Textures/TextureHelpers.h"
13 #include "Common/RenderView.h"
14 #include "Common/ReverseDepth.h"
15 #include "CompiledRenderObject.h"
17 #if defined(FEATURE_SVO_GI)
22 ETEX_Format
CShadowMapStage::GetShadowTexFormat(const SShadowConfig
& shadowConfig
, EPass passID
) const
26 case ePass_DirectionalLight
:
27 case ePass_DirectionalLightRSM
:
28 return CRendererResources::s_hwTexFormatSupport
.GetClosestFormatSupported(
29 shadowConfig
.nTexFormat
== 0 ? eTF_D32F
:
30 (shadowConfig
.nTexFormat
== 1 ? eTF_D16
: eTF_D24S8
));
32 case ePass_DirectionalLightCached
:
33 return CRendererResources::s_hwTexFormatSupport
.GetClosestFormatSupported(
34 shadowConfig
.nCacheFormat
== 0 ? eTF_D32F
: eTF_D16
);
36 case ePass_LocalLightRSM
:
37 case ePass_LocalLight
:
38 return CRendererResources::s_hwTexFormatSupport
.GetClosestFormatSupported(
39 shadowConfig
.nTexFormat
== 0 ? eTF_D32F
: eTF_D16
);
46 CShadowMapStage::CShadowMapStage(CGraphicsPipeline
& graphicsPipeline
)
47 : CGraphicsPipelineStage(graphicsPipeline
)
48 , m_CopyShadowMapPass(&graphicsPipeline
)
49 , m_ClearShadowPoolDepthPass(&graphicsPipeline
)
50 , m_ClearShadowPoolColorPass(&graphicsPipeline
)
51 , m_ClearShadowPoolNormalsPass(&graphicsPipeline
)
52 , m_perPassResources()
53 , m_shadowsLocalLightsLinearizeDepth(1)
54 , m_pTexRT_ShadowPool(nullptr)
57 void CShadowMapStage::Init()
59 std::string name
= "$RT_ShadowPool" + m_graphicsPipeline
.GetUniqueIdentifierName();
60 m_pTexRT_ShadowPool
= CTexture::GetOrCreateTextureObject(name
.c_str(), 0, 0, 1, eTT_2D
, FT_DONT_STREAM
| FT_USAGE_DEPTHSTENCIL
, eTF_Unknown
);
62 // init per pass resource set template
64 const EShaderStage shaderStages
= EShaderStage_Vertex
| EShaderStage_Hull
| EShaderStage_Domain
| EShaderStage_Pixel
;
66 m_perPassResources
.SetTexture(EPerPassTexture_PerlinNoiseMap
, CRendererResources::s_pTexNULL
, EDefaultResourceViews::Default
, EShaderStage_Vertex
);
67 m_perPassResources
.SetTexture(EPerPassTexture_WindGrid
, CRendererResources::s_pTexNULL
, EDefaultResourceViews::Default
, EShaderStage_Vertex
);
68 m_perPassResources
.SetTexture(EPerPassTexture_TerrainElevMap
, CRendererResources::s_pTexNULL
, EDefaultResourceViews::Default
, EShaderStage_Vertex
);
69 m_perPassResources
.SetTexture(EPerPassTexture_TerrainBaseMap
, CRendererResources::s_pTexNULL
, EDefaultResourceViews::sRGB
, EShaderStage_Pixel
);
71 m_perPassResources
.SetConstantBuffer(eConstantBufferShaderSlot_PerPass
, CDeviceBufferManager::GetNullConstantBuffer(), shaderStages
);
72 m_perPassResources
.SetConstantBuffer(eConstantBufferShaderSlot_PerView
, CDeviceBufferManager::GetNullConstantBuffer(), shaderStages
);
74 auto materialSamplers
= m_graphicsPipeline
.GetDefaultMaterialSamplers();
75 for (size_t i
= 0; i
< materialSamplers
.size(); ++i
)
76 m_perPassResources
.SetSampler(EEfResSamplers(i
), materialSamplers
[i
], shaderStages
);
78 // hardcoded point samplers
79 m_perPassResources
.SetSampler(8, EDefaultSamplerStates::PointWrap
, shaderStages
);
80 m_perPassResources
.SetSampler(9, EDefaultSamplerStates::PointClamp
, shaderStages
);
83 m_graphicsPipeline
.SetParticleBuffers(true, m_perPassResources
, EDefaultResourceViews::Default
, EShaderStage_AllWithoutCompute
);
86 // Create resource layout
87 m_pResourceLayout
= m_graphicsPipeline
.CreateScenePassLayout(m_perPassResources
);
89 // Freeze resource-set layout (assert will fire when violating the constraint)
90 m_perPassResources
.AcceptChangedBindPoints();
93 int nShadowTexFormat
= CRendererCVars::CV_r_shadowtexformat
;
95 int nShadowPoolSize
= 2048;
96 if (ICVar
* pShadowsPoolSizeCVar
= iConsole
->GetCVar("e_ShadowsPoolSize"))
97 nShadowPoolSize
= pShadowsPoolSizeCVar
->GetIVal();
99 int nShadowCacheFormat
= CRendererCVars::CV_r_ShadowsCacheFormat
;
100 int nShadowCacheLODs
= CRendererCVars::CV_r_ShadowsCache
;
102 int nShadowCacheCascades
= 0;
103 if (ICVar
* pGsmLodsVar
= gEnv
->pConsole
->GetCVar("e_GsmLodsNum"))
104 nShadowCacheCascades
= pGsmLodsVar
->GetIVal();
106 nShadowCacheCascades
= gEnv
->pSystem
->GetConfigSpec() == CONFIG_LOW_SPEC
? 4 : 5;
108 StaticArray
<int, MAX_GSM_LODS_NUM
> nResolutions
= gRenDev
->GetCachedShadowsResolution();
110 const SShadowConfig shadowConfig
= { nShadowTexFormat
, nShadowPoolSize
, nShadowCacheFormat
, nShadowCacheLODs
, nShadowCacheCascades
, nResolutions
};
111 ReAllocateResources(shadowConfig
);
114 // Providing the right texture is not necessary at all since shadow map rendering is using texture from depth target pool.
115 // It is only necessary to provide a texture with right format.
117 _smart_ptr
<CTexture
> pDummyDL
= CTexture::GetOrCreateTextureObject("DL_DUMMY", 0, 0, 1,
118 m_pTexRT_ShadowPool
->GetTextureType(),
119 m_pTexRT_ShadowPool
->GetFlags(),
120 GetShadowTexFormat(shadowConfig
, ePass_DirectionalLight
));
122 _smart_ptr
<CTexture
> pDummyDLC
= CTexture::GetOrCreateTextureObject("DLC_DUMMY", 0, 0, 1,
123 m_pTexRT_ShadowPool
->GetTextureType(),
124 m_pTexRT_ShadowPool
->GetFlags(),
125 GetShadowTexFormat(shadowConfig
, ePass_DirectionalLightCached
));
127 _smart_ptr
<CTexture
> pDummyLL
= CTexture::GetOrCreateTextureObject("LL_DUMMY", 0, 0, 1,
128 m_pTexRT_ShadowPool
->GetTextureType(),
129 m_pTexRT_ShadowPool
->GetFlags(),
130 GetShadowTexFormat(shadowConfig
, ePass_LocalLight
));
132 _smart_ptr
<CTexture
> pDummyRsmDepth
= m_pTexRT_ShadowPool
;
133 _smart_ptr
<CTexture
> pDummyRsmPoolDepth
= m_pTexRT_ShadowPool
;
135 #if defined(FEATURE_SVO_GI)
136 CSvoRenderer::GetRsmTextures(m_pRsmColorTex
, m_pRsmNormalTex
, m_pRsmPoolColorTex
, m_pRsmPoolNormalTex
);
138 if (!CTexture::IsTextureExist(m_pRsmColorTex
))
140 pDummyRsmDepth
= CTexture::GetOrCreateTextureObject("SVO_PRJ_DEPTH_DIRECTIONAL_LIGHT_DUMMY", 0, 0, 1,
141 m_pTexRT_ShadowPool
->GetTextureType(),
142 m_pTexRT_ShadowPool
->GetFlags(),
143 GetShadowTexFormat(shadowConfig
, ePass_DirectionalLightRSM
));
146 if (!CTexture::IsTextureExist(m_pRsmPoolColorTex
))
148 pDummyRsmPoolDepth
= CTexture::GetOrCreateTextureObject("SVO_PRJ_DEPTH_LOCAL_LIGHT_DUMMY", 0, 0, 1,
149 m_pTexRT_ShadowPool
->GetTextureType(),
150 m_pTexRT_ShadowPool
->GetFlags(),
151 GetShadowTexFormat(shadowConfig
, ePass_LocalLightRSM
));
155 // preallocate typically used passes (NOTE: at least one pass is needed for PSO compilation)
157 m_ShadowMapPasses
[ePass_DirectionalLight
].Init(this, 8, pDummyDL
, nullptr, nullptr);
158 m_ShadowMapPasses
[ePass_DirectionalLightCached
].Init(this, 8, pDummyDLC
, nullptr, nullptr);
159 m_ShadowMapPasses
[ePass_LocalLight
].Init(this, 16, pDummyLL
, nullptr, nullptr);
160 m_ShadowMapPasses
[ePass_DirectionalLightRSM
].Init(this, 1, pDummyRsmDepth
, m_pRsmColorTex
, m_pRsmNormalTex
);
161 m_ShadowMapPasses
[ePass_LocalLightRSM
].Init(this, 1, pDummyRsmPoolDepth
, m_pRsmPoolColorTex
, m_pRsmPoolNormalTex
);
167 void CShadowMapStage::ReAllocateResources(const SShadowConfig shadowConfig
)
169 ETEX_Format eShadowTexFormat
= shadowConfig
.nTexFormat
== 1 ? eTF_D16
: eTF_D32F
;
171 // =======================================
172 // resize shadow pool if required
174 const int shadowPoolSize
= shadowConfig
.nPoolSize
;
176 m_pTexRT_ShadowPool
->Invalidate(shadowPoolSize
, shadowPoolSize
, eShadowTexFormat
);
177 if (!CTexture::IsTextureExist(m_pTexRT_ShadowPool
))
179 #if !defined(_RELEASE) && !CRY_PLATFORM_WINDOWS
180 static int reallocationCount
= 0;
181 assert(reallocationCount
== 0); // don't want any realloc on consoles
185 m_pTexRT_ShadowPool
->CreateDepthStencil(eShadowTexFormat
, ColorF(Clr_FarPlane
.r
, 5.f
, 0.f
, 0.f
));
189 // =======================================
191 const auto& nResolutions
= shadowConfig
.nCacheResolutions
;
192 const ETEX_Format texFormat
= shadowConfig
.nCacheFormat
== 0 ? eTF_D32F
: eTF_D16
;
193 const int cachedShadowsStart
= clamp_tpl(shadowConfig
.nCacheLODs
, 0, MAX_GSM_LODS_NUM
- 1);
194 const int cachedCascadesCount
= cachedShadowsStart
> 0 ? clamp_tpl(shadowConfig
.nCacheCascades
- cachedShadowsStart
+ 1, 0, MAX_GSM_LODS_NUM
) : 0;
196 for (int i
= 0; i
< MAX_GSM_LODS_NUM
; ++i
)
198 _smart_ptr
<CTexture
>& pTx
= m_ShadowMapCache
[i
];
203 cry_sprintf(szName
, "$ShadowMapCached_%d_%d", i
, m_graphicsPipeline
.GetUniqueIdentifierName().c_str());
204 // Only look for a (possibly) existing CTexture object (without re-creating the device-resource)
205 pTx
= CTexture::GetOrCreateTextureObject(szName
, nResolutions
[i
], nResolutions
[i
], 1, eTT_2D
, FT_DONT_STREAM
, texFormat
);
208 // Check if the embedded device-resource matches our config and re-create it when it differs only
209 pTx
->Invalidate(nResolutions
[i
], nResolutions
[i
], texFormat
);
211 // delete existing texture in case it's not needed anymore
212 if (CTexture::IsTextureExist(pTx
) && nResolutions
[i
] == 0)
213 pTx
->ReleaseDeviceTexture(false);
215 // allocate texture directly for all cached cascades
216 if (!CTexture::IsTextureExist(pTx
) && nResolutions
[i
] > 0 && i
< cachedCascadesCount
)
218 CryLog("Allocating shadow map cache %d x %d: %.2f MB", nResolutions
[i
], nResolutions
[i
], sqr(nResolutions
[i
]) * CTexture::BitsPerPixel(texFormat
) / (1024.f
* 1024.f
* 8.f
));
219 pTx
->CreateDepthStencil(texFormat
, Clr_FarPlane
);
224 // =======================================
225 // allocate shadow maps for dynamic frustums
226 for (int lightType
= ePass_DirectionalLight
; lightType
<= ePass_DirectionalLightCached
; ++lightType
)
228 for (auto& cachedPass
: m_ShadowMapPasses
[lightType
])
230 if (cachedPass
.m_eFrustumType
== EFrustumType::e_GsmDynamic
||
231 cachedPass
.m_eFrustumType
== EFrustumType::e_GsmDynamicDistance
||
232 cachedPass
.m_eFrustumType
== EFrustumType::e_PerObject
||
233 cachedPass
.m_eFrustumType
== EFrustumType::e_Nearest
)
235 ETEX_Format texFormat
= GetShadowTexFormat(shadowConfig
, EPass(lightType
));
237 if (cachedPass
.m_pDepthTarget
)
239 const int width
= cachedPass
.m_pDepthTarget
->GetWidth();
240 const int height
= cachedPass
.m_pDepthTarget
->GetHeight();
242 // Check if the embedded device-resource matches our config and re-create it when it differs only
243 cachedPass
.m_pDepthTarget
->Invalidate(width
, height
, texFormat
);
245 if (!CTexture::IsTextureExist(cachedPass
.m_pDepthTarget
))
247 cachedPass
.m_pDepthTarget
->CreateDepthStencil(texFormat
, Clr_FarPlane
);
254 // =======================================
256 CRendererResources::s_ptexFarPlane
->Invalidate(8, 8, eShadowTexFormat
); // 1x HTILE/DepthTile
257 if (!CTexture::IsTextureExist(CRendererResources::s_ptexFarPlane
))
259 CRendererResources::s_ptexFarPlane
->CreateDepthStencil(eShadowTexFormat
, Clr_FarPlane
);
260 CClearSurfacePass::Execute(CRendererResources::s_ptexFarPlane
, CLEAR_ZBUFFER
, Clr_FarPlane
.r
, Val_Unused
);
265 void CShadowMapStage::OnEntityDeleted(IRenderNode
* pRenderNode
)
267 for (int lightType
= ePass_DirectionalLight
; lightType
<= ePass_LocalLightRSM
; ++lightType
)
269 for (auto& cachedPass
: m_ShadowMapPasses
[lightType
])
271 if (cachedPass
.m_pLightOwner
== pRenderNode
)
273 if (cachedPass
.m_eFrustumType
== EFrustumType::e_GsmDynamic
||
274 cachedPass
.m_eFrustumType
== EFrustumType::e_GsmDynamicDistance
||
275 cachedPass
.m_eFrustumType
== EFrustumType::e_PerObject
||
276 cachedPass
.m_eFrustumType
== EFrustumType::e_Nearest
)
278 cachedPass
.m_pDepthTarget
->ReleaseDeviceTexture(false);
281 cachedPass
.m_pLightOwner
= nullptr;
287 size_t CShadowMapStage::GetAllocatedMemory()
289 std::map
<const void*, size_t> textureSet
;
291 // Prevent re-use of textures to contribute more than once to allocated size
292 for (int lightType
= ePass_DirectionalLight
; lightType
<= ePass_LocalLightRSM
; ++lightType
)
294 for (const auto& cachedPass
: m_ShadowMapPasses
[lightType
])
296 if (const auto* depthTarget
= cachedPass
.m_pDepthTarget
.get())
297 textureSet
[depthTarget
] = depthTarget
->GetActualSize();
302 for (auto stat
: textureSet
)
303 sizeSum
+= stat
.second
;
307 void CShadowMapStage::OnCVarsChanged(const CCVarUpdateRecorder
& cvarUpdater
)
309 if (cvarUpdater
.GetCVar("r_ShadowsLocalLightsLinearizeDepth"))
311 m_shadowsLocalLightsLinearizeDepth
= cvarUpdater
.GetCVar("r_ShadowsLocalLightsLinearizeDepth")->intValue
;
314 if (cvarUpdater
.GetCVar("r_ShadowTexFormat") ||
315 cvarUpdater
.GetCVar("e_ShadowsPoolSize") ||
316 cvarUpdater
.GetCVar("r_ShadowsCacheFormat") ||
317 cvarUpdater
.GetCVar("r_ShadowsCache") ||
318 cvarUpdater
.GetCVar("r_ShadowsCacheResolutions") ||
319 cvarUpdater
.GetCVar("e_GsmLodsNum"))
321 int nShadowTexFormat
= CRendererCVars::CV_r_shadowtexformat
;
322 if (cvarUpdater
.GetCVar("r_ShadowTexFormat"))
323 nShadowTexFormat
= cvarUpdater
.GetCVar("r_ShadowTexFormat")->intValue
;
325 int nShadowPoolSize
= 2048;
326 if (cvarUpdater
.GetCVar("e_ShadowsPoolSize"))
327 nShadowPoolSize
= cvarUpdater
.GetCVar("e_ShadowsPoolSize")->intValue
;
328 else if (ICVar
* pShadowsPoolSizeCVar
= iConsole
->GetCVar("e_ShadowsPoolSize"))
329 nShadowPoolSize
= pShadowsPoolSizeCVar
->GetIVal();
331 int nShadowCacheFormat
= CRendererCVars::CV_r_ShadowsCacheFormat
;
332 if (cvarUpdater
.GetCVar("r_ShadowsCacheFormat"))
333 nShadowCacheFormat
= cvarUpdater
.GetCVar("r_ShadowsCacheFormat")->intValue
;
335 int nShadowCacheLODs
= CRendererCVars::CV_r_ShadowsCache
;
336 if (cvarUpdater
.GetCVar("r_ShadowsCache"))
337 nShadowCacheLODs
= cvarUpdater
.GetCVar("r_ShadowsCache")->intValue
;
339 int nShadowCacheCascades
= 0;
340 if (cvarUpdater
.GetCVar("e_GsmLodsNum"))
341 nShadowCacheCascades
= cvarUpdater
.GetCVar("e_GsmLodsNum")->intValue
;
342 else if (ICVar
* pGsmLodsVar
= gEnv
->pConsole
->GetCVar("e_GsmLodsNum"))
343 nShadowCacheCascades
= pGsmLodsVar
->GetIVal();
345 nShadowCacheCascades
= gEnv
->pSystem
->GetConfigSpec() == CONFIG_LOW_SPEC
? 4 : 5;
347 StaticArray
<int, MAX_GSM_LODS_NUM
> nResolutions
= gRenDev
->GetCachedShadowsResolution();
349 ReAllocateResources({ nShadowTexFormat
, nShadowPoolSize
, nShadowCacheFormat
, nShadowCacheLODs
, nShadowCacheCascades
, nResolutions
});
353 void CShadowMapStage::SetRenderView(CRenderView
* pRenderView
)
355 m_pRenderView
= pRenderView
;
359 // Cleanup dangling pointers
361 for (CShadowMapPassGroup
& passGroup
: m_ShadowMapPasses
)
363 for (size_t i
= 0, count
= passGroup
.GetCount(); i
< count
; ++i
)
365 passGroup
[i
].m_pFrustumToRender
= nullptr;
371 bool CShadowMapStage::CreatePipelineState(const SGraphicsPipelineStateDescription
& description
, EPass passID
, CDeviceGraphicsPSOPtr
& outPSO
)
375 CShader
* pShader
= static_cast<CShader
*>(description
.shaderItem
.m_pShader
);
376 SShaderTechnique
* pTechnique
= pShader
->GetTechnique(description
.shaderItem
.m_nTechnique
, description
.technique
, true);
380 CShaderResources
* pRes
= static_cast<CShaderResources
*>(description
.shaderItem
.m_pShaderResources
);
381 if (pRes
->m_ResFlags
& MTL_FLAG_NOSHADOW
)
384 SShaderPass
* pShaderPass
= &pTechnique
->m_Passes
[0];
385 uint64 objectFlags
= description
.objectFlags
;
387 CDeviceGraphicsPSODesc
psoDesc(m_pResourceLayout
, description
);
388 psoDesc
.m_bDynamicDepthBias
= true;
390 // Handle quality flags
391 CGraphicsPipeline::ApplyShaderQuality(psoDesc
, gcpRendD3D
->GetShaderProfile(pShader
->m_eShaderType
));
393 ///////////////////////////////////
394 //SStateRaster curRS = rd->m_StatesRS[rd->m_nCurStateRS];
395 //if (CV_r_ShadowGenDepthClip==0)
397 // if( rTI.m_vFrustumInfo.x > 100.0f )
399 // SStateRaster customRS = curRS;
400 // customRS.Desc.DepthClipEnable = false;
401 // rd->SetRasterState(&customRS);
405 // Set resource states
406 bool bTwoSided
= false;
408 if (pRes
->m_ResFlags
& MTL_FLAG_2SIDED
)
411 if (pRes
->IsAlphaTested())
412 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_ALPHATEST
];
414 if (passID
== ePass_DirectionalLightRSM
|| passID
== ePass_LocalLightRSM
)
416 if (pRes
->m_Textures
[EFTT_DIFFUSE
] && pRes
->m_Textures
[EFTT_DIFFUSE
]->m_Ext
.m_pTexModifier
)
417 psoDesc
.m_ShaderFlags_MD
|= pRes
->m_Textures
[EFTT_DIFFUSE
]->m_Ext
.m_nUpdateFlags
;
420 // Merge EDeformType into EVertexModifier to save space/parameters
421 if (pRes
->m_pDeformInfo
)
422 psoDesc
.m_ShaderFlags_MDV
|= EVertexModifier(pRes
->m_pDeformInfo
->m_eType
);
425 if (m_shadowsLocalLightsLinearizeDepth
== 1)
427 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_SHADOW_DEPTH_OUTPUT_LINEAR
];
431 psoDesc
.m_bAllowTesselation
= false;
432 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_NO_TESSELLATION
];
434 #ifdef TESSELLATION_RENDERER
435 const bool bHasTesselationShaders
= pShaderPass
&& pShaderPass
->m_HShader
&& pShaderPass
->m_DShader
;
436 if (bHasTesselationShaders
&& (!(objectFlags
& FOB_NEAREST
) && (objectFlags
& FOB_ALLOW_TESSELLATION
)))
438 psoDesc
.m_ShaderFlags_RT
&= ~g_HWSR_MaskBit
[HWSR_NO_TESSELLATION
];
439 psoDesc
.m_bAllowTesselation
= true;
443 psoDesc
.m_CullMode
= bTwoSided
? eCULL_None
: ((pShaderPass
&& pShaderPass
->m_eCull
!= -1) ? (ECull
)pShaderPass
->m_eCull
: eCULL_Back
);
444 if (pShader
->m_eSHDType
== eSHDT_Terrain
)
446 //Flipped matrix for point light sources
447 if (passID
== ePass_DirectionalLight
|| passID
== ePass_DirectionalLightCached
)
448 psoDesc
.m_CullMode
= eCULL_None
;
450 psoDesc
.m_CullMode
= eCULL_Front
; //front faces culling by default for terrain
453 if (passID
== ePass_DirectionalLight
|| passID
== ePass_DirectionalLightCached
|| passID
== ePass_DirectionalLightRSM
)
455 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_HW_PCF_COMPARE
];
457 else if (passID
== ePass_LocalLight
|| passID
== ePass_LocalLightRSM
)
459 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_HW_PCF_COMPARE
];
460 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_CUBEMAP0
];
463 if (psoDesc
.m_CullMode
!= eCULL_None
)
465 psoDesc
.m_CullMode
= (psoDesc
.m_CullMode
== eCULL_Front
) ? eCULL_Back
: eCULL_Front
;
469 if (passID
== ePass_DirectionalLightRSM
|| passID
== ePass_LocalLightRSM
)
471 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_SAMPLE4
];
473 if (!bTwoSided
&& psoDesc
.m_CullMode
== eCULL_Front
)
474 psoDesc
.m_CullMode
= eCULL_Back
;
476 if (objectFlags
& FOB_DECAL_TEXGEN_2D
)
477 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_DECAL_TEXGEN_2D
];
479 if ((objectFlags
& FOB_BLEND_WITH_TERRAIN_COLOR
)) // && rRP.m_pCurObject->m_nTextureID > 0
480 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_BLEND_WITH_TERRAIN_COLOR
];
483 psoDesc
.m_ShaderFlags_MDV
|= pShader
->m_nMDV
;
484 if (objectFlags
& FOB_OWNER_GEOMETRY
)
485 psoDesc
.m_ShaderFlags_MDV
&= ~MDV_DEPTH_OFFSET
;
486 if (objectFlags
& FOB_BENDED
)
487 psoDesc
.m_ShaderFlags_MDV
|= MDV_BENDING
;
489 if (!(objectFlags
& FOB_TRANS_MASK
)) //&& gRenDev->m_RP.m_RIs[0].Num() <= 1
490 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_OBJ_IDENTITY
];
492 if (objectFlags
& FOB_NEAREST
)
493 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_NEAREST
];
494 if (objectFlags
& FOB_DISSOLVE
)
495 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_DISSOLVE
];
496 if (psoDesc
.m_RenderState
& GS_ALPHATEST
)
497 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_ALPHATEST
];
499 if (psoDesc
.m_bAllowTesselation
&& (psoDesc
.m_PrimitiveType
< ept1ControlPointPatchList
|| psoDesc
.m_PrimitiveType
> ept4ControlPointPatchList
))
501 psoDesc
.m_PrimitiveType
= ept3ControlPointPatchList
;
502 psoDesc
.m_ObjectStreamMask
|= VSM_NORMALS
;
505 // rendertarget and depth stencil format
506 psoDesc
.m_pRenderPass
= m_ShadowMapPasses
[passID
][0].GetRenderPass();
508 #if (CRY_RENDERER_DIRECT3D >= 120)
509 // emulate slope scaled bias in shader
510 if (passID
== ePass_DirectionalLight
|| passID
== ePass_DirectionalLightCached
|| passID
== ePass_DirectionalLightRSM
)
512 psoDesc
.m_ShaderFlags_RT
|= g_HWSR_MaskBit
[HWSR_SAMPLE0
];
517 outPSO
= GetDeviceObjectFactory().CreateGraphicsPSO(psoDesc
);
518 return outPSO
!= nullptr;
521 bool CShadowMapStage::CreatePipelineStates(DevicePipelineStatesArray
* pStateArray
, const SGraphicsPipelineStateDescription
& stateDesc
, CGraphicsPipelineStateLocalCache
* pStateCache
)
523 DevicePipelineStatesArray
& stageStates
= pStateArray
[StageID
];
525 if (pStateCache
->Find(stateDesc
, stageStates
))
528 bool bFullyCompiled
= true;
530 for (EPass passID
= ePass_First
; passID
< ePass_Count
; passID
= EPass(passID
+ 1))
532 assert(passID
< stageStates
.size());
533 bFullyCompiled
&= CreatePipelineState(stateDesc
, passID
, stageStates
[passID
]);
538 pStateCache
->Put(stateDesc
, stageStates
);
541 return bFullyCompiled
;
544 bool CShadowMapStage::CanRenderCachedShadows(const CCompiledRenderObject
* obj
) const
546 return obj
&& obj
->m_pso
[StageID
][ePass_DirectionalLightCached
] && obj
->m_pso
[StageID
][ePass_DirectionalLightCached
] -> IsValid();
549 void CShadowMapStage::Update()
551 PROFILE_LABEL_SCOPE("SHADOWMAP_PREPARE");
553 CRenderView
* pRenderView
= RenderView();
555 // compile shadow render items
556 pRenderView
->PrepareShadowViews();
558 // prepare the shadow pool
559 m_graphicsPipeline
.GetDeferredShading()->SetupPasses(pRenderView
);
561 // now prepare passes for each frustum
562 for (auto& passGroup
: m_ShadowMapPasses
)
565 for (auto frustumType
= CRenderView::eShadowFrustumRenderType_First
;
566 frustumType
!= CRenderView::eShadowFrustumRenderType_Count
;
567 frustumType
= CRenderView::eShadowFrustumRenderType(frustumType
+ 1))
569 for (auto& pFrustumToRender
: pRenderView
->GetShadowFrustumsByType(frustumType
))
571 CRY_ASSERT(pRenderView
->GetFrameId() == pFrustumToRender
->pShadowsView
->GetFrameId());
572 PrepareShadowPasses(*pFrustumToRender
, frustumType
);
576 // clear the shadow maps we will use
577 if (CRendererCVars::CV_r_ShadowMapsUpdate
)
579 ClearShadowMaps(m_ShadowMapPasses
);
583 void CShadowMapStage::PrepareShadowPasses(SShadowFrustumToRender
& frustumToRender
, CRenderView::eShadowFrustumRenderType frustumRenderType
)
585 const auto* pMainView
= RenderView();
586 auto* pShadowView
= reinterpret_cast<CRenderView
*>(frustumToRender
.pShadowsView
.get());
587 auto* pFrustum
= frustumToRender
.pFrustum
.get();
588 CRY_ASSERT(pFrustum
->bRestrictToRT
);
590 ProfileLabel profileLabel
;
592 PreparePassIDForFrustum(frustumToRender
, frustumRenderType
, passID
, profileLabel
);
594 const auto nSides
= frustumToRender
.pFrustum
->GetNumSides();
595 for (int side
= 0; side
< nSides
; side
++)
597 // assign empty shadow map
598 frustumToRender
.pFrustum
->pDepthTex
= CRendererResources::s_ptexFarPlane
;
600 if (pFrustum
->ShouldSample(side
))
602 CShadowMapPass
& curPass
= m_ShadowMapPasses
[passID
].AddPass();
603 cry_strcpy(curPass
.m_ProfileLabel
, profileLabel
);
605 if (PrepareOutputsForPass(frustumToRender
, side
, curPass
))
607 curPass
.m_pFrustumToRender
= &frustumToRender
;
608 curPass
.m_eFrustumType
= frustumToRender
.pFrustum
->m_eFrustumType
;
609 curPass
.m_pLightOwner
= frustumToRender
.pFrustum
->pLightOwner
;
610 curPass
.m_nShadowFrustumSide
= side
;
611 curPass
.m_eShadowPassID
= passID
;
613 PrepareShadowPassForFrustum(frustumToRender
, side
, curPass
);
614 UpdateShadowFrustumFromPass(curPass
, *pFrustum
);
616 // Symmetric to MT-code, see: CD3D9Renderer::PrepareShadowGenForFrustum
617 curPass
.m_bRequiresRender
=
618 (CRendererCVars::CV_r_ShadowMapsUpdate
&& !pShadowView
->GetRenderItems(ERenderListID(side
)).empty()) ||
619 (pFrustum
->m_eFrustumType
== ShadowMapFrustum::e_GsmDynamicDistance
) ||
620 (pFrustum
->m_eFrustumType
== ShadowMapFrustum::e_GsmCached
&& !pFrustum
->bIncrementalUpdate
) ||
621 (pFrustum
->m_eFrustumType
== ShadowMapFrustum::e_GsmDynamic
&& pFrustum
->ShouldUpdate(side
));
623 curPass
.SetLabel(curPass
.m_ProfileLabel
);
624 curPass
.SetPassResources(m_pResourceLayout
, curPass
.GetResources());
626 curPass
.PrepareResources(pMainView
);
627 curPass
.PrepareRenderPassForUse(GetDeviceObjectFactory().GetCoreCommandList());
631 m_ShadowMapPasses
[passID
].UndoAddPass();
637 void CShadowMapStage::PreparePassIDForFrustum(const SShadowFrustumToRender
& frustumToRender
, CRenderView::eShadowFrustumRenderType frustumRenderType
, EPass
& passID
, ProfileLabel
& profileLabel
) const
639 const ShadowMapFrustum
& frustum
= *frustumToRender
.pFrustum
;
641 #if defined(FEATURE_SVO_GI)
642 if (CSvoRenderer::GetRsmColorMap(m_graphicsPipeline
, frustum
, true) && CSvoRenderer::GetRsmNormlMap(m_graphicsPipeline
, frustum
, true))
644 if (frustumRenderType
== CRenderView::eShadowFrustumRenderType_SunDynamic
)
646 passID
= ePass_DirectionalLightRSM
;
647 cry_sprintf(profileLabel
, "SUN FRUSTUM (RSM) %i", frustum
.nShadowMapLod
);
651 passID
= ePass_LocalLightRSM
;
652 cry_sprintf(profileLabel
, "LOCAL LIGHT (RSM) %s", frustumToRender
.pLight
->m_sName
);
658 switch (frustumRenderType
)
660 case CRenderView::eShadowFrustumRenderType_SunDynamic
:
662 passID
= ePass_DirectionalLight
;
663 const char* szLabel
= frustum
.m_eFrustumType
== ShadowMapFrustum::e_GsmDynamicDistance
? "SUN DISTANCE FRUSTUM %i" : "SUN FRUSTUM %i";
664 cry_sprintf(profileLabel
, szLabel
, frustum
.nShadowMapLod
);
667 case CRenderView::eShadowFrustumRenderType_SunCached
:
669 passID
= ePass_DirectionalLightCached
;
670 cry_sprintf(profileLabel
, "SUN CACHED %i", frustum
.nShadowMapLod
);
673 case CRenderView::eShadowFrustumRenderType_HeightmapAO
:
675 passID
= ePass_DirectionalLightCached
;
676 cry_sprintf(profileLabel
, "HEIGHTMAP AO");
679 case CRenderView::eShadowFrustumRenderType_Custom
:
681 passID
= ePass_DirectionalLight
;
683 if (frustum
.m_eFrustumType
== ShadowMapFrustum::e_Nearest
)
685 cry_sprintf(profileLabel
, "SUN NEAREST");
689 cry_sprintf(profileLabel
, "SUN PER OBJECT");
693 case CRenderView::eShadowFrustumRenderType_LocalLight
:
695 passID
= ePass_LocalLight
;
696 cry_sprintf(profileLabel
, "LOCAL LIGHT %s", frustumToRender
.pLight
->m_sName
);
703 bool CShadowMapStage::PrepareOutputsForPass(const SShadowFrustumToRender
& frustumToRender
, int nSide
, CShadowMapPass
& targetPass
) const
705 const ShadowMapFrustum
& frustum
= *frustumToRender
.pFrustum
;
708 _smart_ptr
<CTexture
> pDepthTarget
;
709 std::array
<CTexture
*, 2> colorTargets
;
710 colorTargets
.fill(nullptr);
711 const CShadowMapPass
* pClearDepthMapProvider
= nullptr;
712 CShadowMapPass::eClearMode clearMode
= CShadowMapPass::eClearMode_Fill
;
714 if (frustum
.bUseShadowsPool
)
716 CRY_ASSERT(!frustum
.IsCached());
718 pDepthTarget
= m_pTexRT_ShadowPool
;
719 clearMode
= CShadowMapPass::eClearMode_FillRect
;
720 frustum
.GetSideViewport(nSide
, arrViewport
);
725 cry_sprintf(pName
, "$%s", targetPass
.m_ProfileLabel
);
727 if (frustum
.m_eFrustumType
== ShadowMapFrustum::e_GsmDynamic
||
728 frustum
.m_eFrustumType
== ShadowMapFrustum::e_PerObject
||
729 frustum
.m_eFrustumType
== ShadowMapFrustum::e_Nearest
)
731 // Only look for a (possibly) existing CTexture object (without re-creating the device-resource)
732 pDepthTarget
= CTexture::GetOrCreateTextureObjectPtr(pName
, frustum
.nTextureWidth
, frustum
.nTextureHeight
, 1, frustum
.m_eReqTT
, FT_USAGE_TEMPORARY
| FT_NOMIPS
| FT_STATE_CLAMP
, frustum
.m_eReqTF
);
734 // Check if the embedded device-resource exist, and only create a new one when this is the first request
735 if (!CTexture::IsTextureExist(pDepthTarget
))
736 pDepthTarget
->CreateDepthStencil(frustum
.m_eReqTF
, frustum
.clearValue
);
740 pDepthTarget
= PrepareOutputsForFrustumWithCaching(pName
, frustum
, pClearDepthMapProvider
, clearMode
);
743 arrViewport
[0] = arrViewport
[1] = 0;
744 arrViewport
[2] = pDepthTarget
? pDepthTarget
->GetWidth() : 0;
745 arrViewport
[3] = pDepthTarget
? pDepthTarget
->GetHeight() : 0;
748 #if defined(FEATURE_SVO_GI)
749 colorTargets
[0] = CSvoRenderer::GetInstance()->GetRsmColorMap(m_graphicsPipeline
, frustum
);
750 colorTargets
[1] = CSvoRenderer::GetInstance()->GetRsmNormlMap(m_graphicsPipeline
, frustum
);
753 targetPass
.m_pDepthTarget
= pDepthTarget
;
754 if (!pDepthTarget
|| !pDepthTarget
->GetDevTexture())
758 targetPass
.m_pClearDepthMapProvider
= pClearDepthMapProvider
;
759 targetPass
.m_clearMode
= clearMode
;
760 targetPass
.SetRenderTargets(pDepthTarget
, colorTargets
[0], colorTargets
[1]);
762 D3DViewPort viewport
= { float(arrViewport
[0]), float(arrViewport
[1]), float(arrViewport
[2]), float(arrViewport
[3]), 0, 1 };
763 targetPass
.SetViewport(viewport
);
768 void CShadowMapStage::UpdateShadowFrustumFromPass(const CShadowMapPass
& sourcePass
, ShadowMapFrustum
& targetFrustum
) const
770 CTexture
* pDepthTarget
= sourcePass
.GetPassDesc().GetDepthTarget().pTexture
;
772 if (targetFrustum
.m_eFrustumType
== ShadowMapFrustum::e_Nearest
)
774 targetFrustum
.fWidthS
*= targetFrustum
.nTexSize
/ float(pDepthTarget
->GetWidth());
775 targetFrustum
.fWidthT
*= targetFrustum
.nTexSize
/ float(pDepthTarget
->GetHeight());
778 targetFrustum
.pDepthTex
= pDepthTarget
;
779 targetFrustum
.nTextureWidth
= pDepthTarget
->GetWidth();
780 targetFrustum
.nTextureHeight
= pDepthTarget
->GetHeight();
781 targetFrustum
.clearValue
= pDepthTarget
->GetClearColor();
783 targetFrustum
.mLightViewMatrix
= sourcePass
.m_ViewProjMatrix
;
784 targetFrustum
.mLightProjMatrix
.SetIdentity();
786 if (sourcePass
.m_pClearDepthMapProvider
)
788 const ShadowMapFrustum
* pSrcFrustum
= sourcePass
.m_pClearDepthMapProvider
->m_pFrustumToRender
->pFrustum
;
790 targetFrustum
.fNearDist
= pSrcFrustum
->fNearDist
;
791 targetFrustum
.fFarDist
= pSrcFrustum
->fFarDist
;
792 targetFrustum
.fRendNear
= pSrcFrustum
->fRendNear
;
793 targetFrustum
.fDepthConstBias
= pSrcFrustum
->fDepthConstBias
;
794 targetFrustum
.fDepthTestBias
= pSrcFrustum
->fDepthTestBias
;
795 targetFrustum
.fDepthSlopeBias
= pSrcFrustum
->fDepthSlopeBias
;
796 targetFrustum
.fDepthBiasClamp
= pSrcFrustum
->fDepthBiasClamp
;
800 _smart_ptr
<CTexture
> CShadowMapStage::PrepareOutputsForFrustumWithCaching(const char* pName
, const ShadowMapFrustum
& frustum
, const CShadowMapPass
*& pClearDepthMapProvider
, CShadowMapPass::eClearMode
& clearMode
) const
802 CRY_ASSERT(frustum
.IsCached() || frustum
.m_eFrustumType
== ShadowMapFrustum::eFrustumType::e_GsmDynamicDistance
);
804 _smart_ptr
<CTexture
> pDepthTarget
;
805 pClearDepthMapProvider
= nullptr;
806 clearMode
= CShadowMapPass::eClearMode_Fill
;
808 if (frustum
.IsCached())
810 if (frustum
.m_eFrustumType
== ShadowMapFrustum::eFrustumType::e_GsmCached
)
812 int nCachedMapIndex
= frustum
.nShadowCacheLod
;
813 CRY_ASSERT(nCachedMapIndex
>= 0 && nCachedMapIndex
< CRY_ARRAY_COUNT(m_ShadowMapCache
));
815 pDepthTarget
= m_ShadowMapCache
[clamp_tpl(nCachedMapIndex
, 0, int(CRY_ARRAY_COUNT(m_ShadowMapCache
) - 1))];
817 else if (frustum
.m_eFrustumType
== ShadowMapFrustum::eFrustumType::e_HeightMapAO
)
819 auto* heightMapAO
= m_graphicsPipeline
.GetStage
<CHeightMapAOStage
>();
820 CRY_ASSERT(heightMapAO
->IsStageActive(EShaderRenderingFlags(0)));
822 pDepthTarget
= heightMapAO
->GetHeightMapAODepthTex(0);
825 clearMode
= frustum
.bIncrementalUpdate
? CShadowMapPass::eClearMode_None
: CShadowMapPass::eClearMode_Fill
;
827 else if (frustum
.m_eFrustumType
== ShadowMapFrustum::eFrustumType::e_GsmDynamicDistance
)
829 // find corresponding cached frustum
830 for (const auto& cachedPass
: m_ShadowMapPasses
[ePass_DirectionalLightCached
])
832 const ShadowMapFrustum
* pCachedFrustum
= cachedPass
.m_pFrustumToRender
->pFrustum
;
833 if (pCachedFrustum
->nShadowMapLod
== frustum
.nShadowMapLod
)
835 pClearDepthMapProvider
= &cachedPass
;
836 clearMode
= CShadowMapPass::eClearMode_CopyDepthMap
;
838 // Only look for a (possibly) existing CTexture object (without re-creating the device-resource)
839 pDepthTarget
= CTexture::GetOrCreateTextureObjectPtr(pName
, frustum
.nTextureWidth
, frustum
.nTextureHeight
, 1, frustum
.m_eReqTT
, FT_USAGE_TEMPORARY
| FT_NOMIPS
| FT_STATE_CLAMP
, frustum
.m_eReqTF
);
841 // Check if the embedded device-resource exist, and only create a new one when this is the first request
842 if (!CTexture::IsTextureExist(pDepthTarget
))
843 pDepthTarget
->CreateDepthStencil(frustum
.m_eReqTF
, frustum
.clearValue
);
853 void CShadowMapStage::PrepareShadowPassForFrustum(const SShadowFrustumToRender
& frustumToRender
, int nSide
, CShadowMapPass
& targetPass
) const
855 const CRenderView
* pMainView
= RenderView();
856 const ShadowMapFrustum
& frustum
= *frustumToRender
.pFrustum
;
858 Vec4 frustumInfo
= Vec4(
859 (CRendererCVars::CV_r_ShadowGenDepthClip
== 0 && frustum
.fRendNear
> 0.0f
) ? frustum
.fRendNear
: frustum
.fNearDist
,
860 (frustum
.m_eFrustumType
== ShadowMapFrustum::e_HeightMapAO
) ? 1.0f
: frustum
.fFarDist
,
861 frustum
.fDepthSlopeBias
,
862 frustum
.fDepthTestBias
865 // get view projection matrix
866 if (!frustum
.bOmniDirectionalShadow
)
868 Matrix44A viewProj
= frustum
.mLightViewMatrix
;
870 if (frustum
.m_eFrustumType
== ShadowMapFrustum::e_Nearest
)
872 const Vec3 camPos
= pMainView
->GetCamera(CCamera::eEye_Left
).GetPosition();
873 AABB aabb
= frustum
.aabbCasters
;
876 Matrix44A view
, proj
;
877 CShadowUtils::GetShadowMatrixForObject(proj
, view
, frustumInfo
, frustum
.vLightSrcRelPos
, aabb
);
879 viewProj
= view
* proj
;
882 Matrix44A viewProjOrig
= viewProj
;
883 if (targetPass
.m_pClearDepthMapProvider
)
885 // If the sub-frustum falls out of the full frustum entirely, then no depth-copy is needed or possible
886 if (!CShadowUtils::GetSubfrustumMatrix(viewProj
, targetPass
.m_pClearDepthMapProvider
->m_pFrustumToRender
->pFrustum
, &frustum
))
887 targetPass
.m_clearMode
= CShadowMapPass::eClearMode_Fill
;
890 targetPass
.m_ViewProjMatrix
= viewProj
;
891 targetPass
.m_ViewProjMatrixOrig
= viewProjOrig
;
892 targetPass
.m_FrustumInfo
= frustumInfo
;
893 targetPass
.SetDepthBias(0.0f
, frustumInfo
.z
, frustum
.fDepthBiasClamp
);
898 CShadowUtils::GetCubemapFrustum(FTYP_SHADOWOMNIPROJECTION
, &frustum
, nSide
, &proj
, &view
);
900 targetPass
.m_ViewProjMatrix
= view
* proj
;
901 targetPass
.m_FrustumInfo
= frustumInfo
;
902 targetPass
.SetDepthBias(0.0f
, 0.0f
, 0.0f
);
905 // Override clear mode for dynamic lights: Cached sides do not need a clear
906 if (frustum
.m_eFrustumType
== ShadowMapFrustum::e_GsmDynamic
&& frustum
.ShouldCache(nSide
))
907 targetPass
.m_clearMode
= CShadowMapPass::eClearMode_None
;
910 void CShadowMapStage::CShadowMapPassGroup::Init(CShadowMapStage
* pStage
, int nSize
, CTexture
* pDepthTarget
, CTexture
* pColorTarget0
, CTexture
* pColorTarget1
)
913 m_Passes
.reserve(nSize
);
917 for (int i
= 0; i
< nSize
; ++i
)
919 m_Passes
.emplace_back(pStage
);
920 m_Passes
.back().SetRenderTargets(pDepthTarget
, pColorTarget0
, pColorTarget1
);
924 CShadowMapStage::CShadowMapPass
& CShadowMapStage::CShadowMapPassGroup::AddPass()
926 if (m_PassCount
>= GetCapacity())
927 m_Passes
.emplace_back(m_pStage
);
929 return m_Passes
[m_PassCount
++];
932 CShadowMapStage::CShadowMapPass::CShadowMapPass(CShadowMapStage
* pStage
)
933 : m_pDepthTarget(nullptr)
934 , m_pFrustumToRender(nullptr)
935 , m_eFrustumType(EFrustumType(0))
936 , m_pLightOwner(nullptr)
937 , m_nShadowFrustumSide(0)
938 , m_eShadowPassID(EPass(0))
939 , m_perPassResources(pStage
->m_perPassResources
) // clone per pass resources from stage
940 , m_ViewProjMatrix(IDENTITY
)
941 , m_ViewProjMatrixOrig(IDENTITY
)
942 , m_pShadowMapStage(pStage
)
944 m_pPerPassResourceSet
= GetDeviceObjectFactory().CreateResourceSet(CDeviceResourceSet::EFlags_ForceSetAllState
);
945 m_pPerPassConstantBuffer
= gcpRendD3D
->m_DevBufMan
.CreateConstantBuffer(sizeof(HLSL_PerPassConstantBuffer_ShadowGen
));
946 m_pPerViewConstantBuffer
= gcpRendD3D
->m_DevBufMan
.CreateConstantBuffer(sizeof(HLSL_PerViewGlobalConstantBuffer
));
949 CShadowMapStage::CShadowMapPass::CShadowMapPass(CShadowMapPass
&& other
)
950 : CSceneRenderPass(std::move(other
))
951 , m_pFrustumToRender(std::move(other
.m_pFrustumToRender
))
952 , m_eFrustumType(std::move(other
.m_eFrustumType
))
953 , m_pLightOwner(std::move(other
.m_pLightOwner
))
954 , m_nShadowFrustumSide(std::move(other
.m_nShadowFrustumSide
))
955 , m_eShadowPassID(std::move(other
.m_eShadowPassID
))
956 , m_bRequiresRender(std::move(other
.m_bRequiresRender
))
957 , m_pPerPassConstantBuffer(std::move(other
.m_pPerPassConstantBuffer
))
958 , m_pPerViewConstantBuffer(std::move(other
.m_pPerViewConstantBuffer
))
959 , m_perPassResources(other
.m_perPassResources
)
960 , m_ViewProjMatrix(std::move(other
.m_ViewProjMatrix
))
961 , m_ViewProjMatrixOrig(std::move(other
.m_ViewProjMatrixOrig
))
962 , m_FrustumInfo(std::move(other
.m_FrustumInfo
))
963 , m_pShadowMapStage(std::move(other
.m_pShadowMapStage
))
964 , m_clearMode(std::move(other
.m_clearMode
))
965 , m_pClearDepthMapProvider(std::move(other
.m_pClearDepthMapProvider
))
967 strncpy(m_ProfileLabel
, other
.m_ProfileLabel
, sizeof(m_ProfileLabel
));
970 bool CShadowMapStage::CShadowMapPass::PrepareResources(const CRenderView
* pMainView
)
972 assert(m_pFrustumToRender
);
973 assert(m_pPerPassResourceSet
);
974 assert(m_pPerViewConstantBuffer
);
975 assert(m_pPerPassConstantBuffer
);
977 ShadowMapFrustum
& frustum
= *m_pFrustumToRender
->pFrustum
;
979 // update per pass textures
981 int nTerrainTex0
= 0, nTerrainTex1
= 0, nTerrainTex2
= 0;
982 ITerrain
* pTerrain
= gEnv
->p3DEngine
->GetITerrain();
984 pTerrain
->GetAtlasTexId(nTerrainTex0
, nTerrainTex1
, nTerrainTex2
);
986 m_perPassResources
.SetTexture(EPerPassTexture_PerlinNoiseMap
, CRendererResources::s_ptexPerlinNoiseMap
, EDefaultResourceViews::Default
, EShaderStage_Vertex
);
987 m_perPassResources
.SetTexture(EPerPassTexture_WindGrid
, CRendererResources::s_ptexWindGrid
, EDefaultResourceViews::Default
, EShaderStage_Vertex
);
988 m_perPassResources
.SetTexture(EPerPassTexture_TerrainBaseMap
, CTexture::GetByID(nTerrainTex0
), EDefaultResourceViews::sRGB
, EShaderStage_Pixel
);
989 m_perPassResources
.SetTexture(EPerPassTexture_TerrainElevMap
, CTexture::GetByID(nTerrainTex2
), EDefaultResourceViews::Default
, EShaderStage_Vertex
);
992 // update per pass samplers
994 const EShaderStage shaderStages
= EShaderStage_Vertex
| EShaderStage_Hull
| EShaderStage_Domain
| EShaderStage_Pixel
;
996 auto materialSamplers
= m_pShadowMapStage
->m_graphicsPipeline
.GetDefaultMaterialSamplers();
997 for (size_t i
= 0; i
< materialSamplers
.size(); ++i
)
998 m_perPassResources
.SetSampler(EEfResSamplers(i
), materialSamplers
[i
], shaderStages
);
1003 CTypedConstantBuffer
<HLSL_PerPassConstantBuffer_ShadowGen
, 256> cb(m_pPerPassConstantBuffer
);
1005 cb
->CP_ShadowGen_LightPos
= Vec4(frustum
.vLightSrcRelPos
+ frustum
.vProjTranslation
, 0);
1006 cb
->CP_ShadowGen_ViewPos
= Vec4(pMainView
->GetCamera(CCamera::eEye_Left
).GetPosition(), 0);
1007 cb
->CP_ShadowGen_DepthTestBias
= Vec4(ZERO
); // TODO
1009 cb
->CP_ShadowGen_FrustrumInfo
= m_FrustumInfo
;
1011 cb
->CP_ShadowGen_VegetationAlphaClamp
= Vec4(ZERO
);
1012 #if defined(FEATURE_SVO_GI)
1013 if (CSvoRenderer
* pSvoRenderer
= CSvoRenderer::GetInstance())
1015 cb
->CP_ShadowGen_VegetationAlphaClamp
.x
= pSvoRenderer
->GetVegetationMaxOpacity();
1021 m_perPassResources
.SetConstantBuffer(eConstantBufferShaderSlot_PerPass
, m_pPerPassConstantBuffer
.get(), EShaderStage_Vertex
| EShaderStage_Hull
| EShaderStage_Domain
| EShaderStage_Pixel
);
1026 SRenderViewInfo viewInfo
;
1027 viewInfo
.pCamera
= &pMainView
->GetCamera(CCamera::eEye_Left
);
1028 viewInfo
.cameraProjZeroMatrix
= m_ViewProjMatrix
;
1029 viewInfo
.cameraProjMatrix
= m_ViewProjMatrix
;
1030 viewInfo
.cameraProjNearestMatrix
= m_ViewProjMatrix
;
1031 viewInfo
.projMatrix
= m_ViewProjMatrix
;
1032 viewInfo
.prevCameraProjMatrix
= m_ViewProjMatrix
;
1033 viewInfo
.prevCameraProjNearestMatrix
= m_ViewProjMatrix
;
1034 viewInfo
.viewport
.width
= m_renderPassDesc
.GetDepthTarget().pTexture
->GetWidth();
1035 viewInfo
.viewport
.height
= m_renderPassDesc
.GetDepthTarget().pTexture
->GetHeight();
1036 viewInfo
.downscaleFactor
= Vec4(1);
1037 viewInfo
.pFrustumPlanes
= frustum
.FrustumPlanes
[0].GetFrustumPlane(0);
1039 // The shadow frustum camera must be used for cameraOrigin and cameraV*.
1040 const CCamera
& shadowCam
= frustum
.pFrustumOwner
->FrustumPlanes
[m_nShadowFrustumSide
];
1041 viewInfo
.cameraOrigin
= shadowCam
.GetPosition();
1042 viewInfo
.cameraVX
= shadowCam
.GetRenderVectorX();
1043 viewInfo
.cameraVY
= shadowCam
.GetRenderVectorY();
1044 viewInfo
.cameraVZ
= shadowCam
.GetRenderVectorZ();
1046 m_pShadowMapStage
->m_graphicsPipeline
.GeneratePerViewConstantBuffer(&viewInfo
, 1, m_pPerViewConstantBuffer
);
1048 m_perPassResources
.SetConstantBuffer(eConstantBufferShaderSlot_PerView
, m_pPerViewConstantBuffer
.get(), EShaderStage_Vertex
| EShaderStage_Hull
| EShaderStage_Domain
| EShaderStage_Pixel
);
1051 // particle resources
1052 m_pShadowMapStage
->m_graphicsPipeline
.SetParticleBuffers(false, m_perPassResources
, EDefaultResourceViews::Default
, EShaderStage_AllWithoutCompute
);
1054 CRY_ASSERT(!m_perPassResources
.HasChangedBindPoints()); // Cannot change resource layout after init. It is baked into the shaders
1055 m_pPerPassResourceSet
->Update(m_perPassResources
);
1056 CRY_ASSERT(m_pPerPassResourceSet
->IsValid());
1057 return m_pPerPassResourceSet
->IsValid();
1060 void CShadowMapStage::CShadowMapPass::PreRender()
1062 if (m_clearMode
== eClearMode_CopyDepthMap
)
1064 CRY_ASSERT(m_pClearDepthMapProvider
);
1065 m_pShadowMapStage
->CopyShadowMap(*m_pClearDepthMapProvider
, *this);
1069 void CShadowMapStage::CopyShadowMap(const CShadowMapPass
& sourcePass
, CShadowMapPass
& targetPass
)
1071 ShadowMapFrustum
* pDst
= targetPass
.m_pFrustumToRender
->pFrustum
;
1072 const ShadowMapFrustum
* pSrc
= sourcePass
.m_pFrustumToRender
->pFrustum
;
1074 CRY_ASSERT(pSrc
->m_eFrustumType
== ShadowMapFrustum::e_GsmCached
);
1075 CRY_ASSERT(pDst
->m_eFrustumType
== ShadowMapFrustum::e_GsmDynamicDistance
);
1076 CRY_ASSERT(pSrc
->nShadowMapLod
== pDst
->nShadowMapLod
);
1078 const bool bEmptySrcFrustum
= !pSrc
->ShouldSample();
1079 const auto& renderItems
= reinterpret_cast<CRenderView
*>(targetPass
.m_pFrustumToRender
->pShadowsView
.get())->GetRenderItems(ERenderListID(0));
1080 const auto& depthTarget
= targetPass
.GetPassDesc().GetDepthTarget();
1082 // do we need to merge static shadows into the dynamic shadow map?
1083 if (bEmptySrcFrustum
|| !renderItems
.empty())
1085 if (bEmptySrcFrustum
)
1087 CClearSurfacePass::Execute(depthTarget
.pTexture
, CLEAR_ZBUFFER
| CLEAR_STENCIL
, Clr_FarPlane
.r
, Val_Stencil
);
1091 static CCryNameTSCRC
tech("ReprojectShadowMap");
1092 CShader
* pShader
= CShaderMan::s_ShaderShadowMaskGen
;
1094 m_CopyShadowMapPass
.SetDepthTarget(depthTarget
.pTexture
, depthTarget
.view
);
1095 m_CopyShadowMapPass
.SetTechnique(pShader
, tech
, 0);
1096 m_CopyShadowMapPass
.SetState(GS_DEPTHWRITE
| GS_DEPTHFUNC_NOTEQUAL
);
1097 m_CopyShadowMapPass
.SetPrimitiveType(CRenderPrimitive::ePrim_ProceduralTriangle
);
1098 m_CopyShadowMapPass
.SetTextureSamplerPair(0, pSrc
->pDepthTex
, EDefaultSamplerStates::LinearClamp
);
1099 m_CopyShadowMapPass
.BeginConstantUpdate();
1101 Matrix44 mReprojDstToSrc
= pDst
->mLightViewMatrix
.GetInverted() * pSrc
->mLightViewMatrix
;
1103 static CCryNameR
paramReprojMatDstToSrc("g_mReprojDstToSrc");
1104 m_CopyShadowMapPass
.SetConstantArray(paramReprojMatDstToSrc
, (Vec4
*) mReprojDstToSrc
.GetData(), 4, eHWSC_Pixel
);
1106 Matrix44 mReprojSrcToDst
= pSrc
->mLightViewMatrix
.GetInverted() * pDst
->mLightViewMatrix
;
1107 static CCryNameR
paramReprojMatSrcToDst("g_mReprojSrcToDst");
1108 m_CopyShadowMapPass
.SetConstantArray(paramReprojMatSrcToDst
, (Vec4
*) mReprojSrcToDst
.GetData(), 4, eHWSC_Pixel
);
1110 m_CopyShadowMapPass
.Execute();
1113 pDst
->shadowCascade
= TRect_tpl
<float>{ 0, 0, static_cast<float>(pDst
->nTextureWidth
), static_cast<float>(pDst
->nTextureHeight
) };
1117 // get crop rectangle for projection
1118 Matrix44r mReproj
= Matrix44r(targetPass
.m_ViewProjMatrixOrig
).GetInverted() * Matrix44r(pSrc
->mLightViewMatrix
);
1119 Vec4r srcClipPosTL
= Vec4r(-1, -1, 0, 1) * mReproj
;
1120 srcClipPosTL
/= srcClipPosTL
.w
;
1122 const float fSnap
= 2.0f
/ pSrc
->pDepthTex
->GetWidth();
1124 crop
.x
= fSnap
* int(srcClipPosTL
.x
/ fSnap
),
1125 crop
.y
= fSnap
* int(srcClipPosTL
.y
/ fSnap
),
1126 crop
.z
= 2.0f
* pDst
->nTextureWidth
/ float(pSrc
->nTextureWidth
),
1127 crop
.w
= 2.0f
* pDst
->nTextureHeight
/ float(pSrc
->nTextureHeight
)
1130 pDst
->shadowCascade
.Min
= {
1131 (crop
.x
* 0.5f
+ 0.5f
) * pSrc
->pDepthTex
->GetWidth() + 0.5f
,
1132 (-(crop
.y
+ crop
.w
) * 0.5f
+ 0.5f
) * pSrc
->pDepthTex
->GetHeight() + 0.5f
1134 pDst
->shadowCascade
.Max
= pDst
->shadowCascade
.Min
+ Vec2_tpl
<float>{
1135 static_cast<float>(pDst
->nTextureWidth
),
1136 static_cast<float>(pDst
->nTextureHeight
)
1139 pDst
->pDepthTex
= pSrc
->pDepthTex
;
1140 pDst
->nTexSize
= pSrc
->nTexSize
;
1141 pDst
->nTextureWidth
= pSrc
->nTextureWidth
;
1142 pDst
->nTextureHeight
= pSrc
->nTextureHeight
;
1143 pDst
->clearValue
= pSrc
->clearValue
;
1146 pDst
->bIncrementalUpdate
= true;
1147 pDst
->fNearDist
= pSrc
->fNearDist
;
1148 pDst
->fFarDist
= pSrc
->fFarDist
;
1149 pDst
->fRendNear
= pSrc
->fRendNear
;
1150 pDst
->fDepthConstBias
= pSrc
->fDepthConstBias
;
1151 pDst
->fDepthTestBias
= pSrc
->fDepthTestBias
;
1152 pDst
->fDepthSlopeBias
= pSrc
->fDepthSlopeBias
;
1153 pDst
->fDepthBiasClamp
= pSrc
->fDepthBiasClamp
;
1156 void CShadowMapStage::ClearShadowMaps(PassGroupList
& shadowMapPasses
)
1158 // clear shadow pool regions first
1159 if (shadowMapPasses
[ePass_LocalLight
].GetCount() > 0 || shadowMapPasses
[ePass_LocalLightRSM
].GetCount() > 0)
1161 std::vector
<D3DRectangle
> clearDepthRects
; clearDepthRects
.reserve(64);
1162 std::vector
<D3DRectangle
> clearColorRects
; clearColorRects
.reserve(64);
1164 EPass passes
[] = { ePass_LocalLight
, ePass_LocalLightRSM
};
1165 for (const auto& pass
: passes
)
1167 for (const auto& localLightPass
: shadowMapPasses
[pass
])
1169 if (localLightPass
.m_clearMode
== CShadowMapPass::eClearMode_None
)
1172 CRY_ASSERT(localLightPass
.GetPassDesc().GetDepthTarget().pTexture
== m_pTexRT_ShadowPool
);
1173 CRY_ASSERT(localLightPass
.m_clearMode
== CShadowMapPass::eClearMode_FillRect
);
1175 clearDepthRects
.push_back(localLightPass
.GetScissorRect());
1177 if (pass
== ePass_LocalLightRSM
)
1179 clearColorRects
.push_back(localLightPass
.GetScissorRect());
1184 if (!clearDepthRects
.empty() || !clearColorRects
.empty())
1186 m_ClearShadowPoolDepthPass
.Execute(m_pTexRT_ShadowPool
, CLEAR_ZBUFFER
| CLEAR_STENCIL
, 1.0f
, 5, clearDepthRects
.size(), clearDepthRects
.data());
1188 #if defined(FEATURE_SVO_GI)
1189 CTexture
* pRsmColor
= CSvoRenderer::GetInstance()->GetRsmPoolCol();
1190 CTexture
* pRsmNormals
= CSvoRenderer::GetInstance()->GetRsmPoolNor();
1192 if (CTexture::IsTextureExist(pRsmColor
) && CTexture::IsTextureExist(pRsmNormals
))
1194 m_ClearShadowPoolColorPass
.Execute(pRsmColor
, Clr_Transparent
, clearColorRects
.size(), clearColorRects
.data());
1195 m_ClearShadowPoolNormalsPass
.Execute(pRsmNormals
, Clr_Transparent
, clearColorRects
.size(), clearColorRects
.data());
1202 // clear remaining depth maps and prepare all passes for use
1203 CDeviceCommandListRef commandList
= GetDeviceObjectFactory().GetCoreCommandList();
1205 for (auto& passGroup
: shadowMapPasses
)
1207 for (auto& curPass
: passGroup
)
1209 if (curPass
.m_clearMode
== CShadowMapPass::eClearMode_Fill
)
1211 const auto& depthTarget
= curPass
.GetPassDesc().GetDepthTarget();
1213 CClearSurfacePass::Execute(depthTarget
.pTexture
, CLEAR_ZBUFFER
, Clr_FarPlane
.r
, Val_Unused
);
1215 for (const auto& colorTarget
: curPass
.GetPassDesc().GetRenderTargets())
1217 if (!colorTarget
.pTexture
)
1220 CClearSurfacePass::Execute(colorTarget
.pTexture
, Clr_Transparent
);
1224 curPass
.PrepareRenderPassForUse(commandList
);
1229 void CShadowMapStage::Execute()
1231 FUNCTION_PROFILER_RENDERER();
1232 PROFILE_LABEL_SCOPE("SHADOWMAPS");
1234 CRenderItemDrawer
& rendItemDrawer
= RenderView()->GetDrawer();
1236 // Cached shadow maps cannot run concurrent due to CopyShadowMap pass
1237 for (auto& curPass
: m_ShadowMapPasses
[ePass_DirectionalLightCached
])
1239 if (curPass
.m_bRequiresRender
)
1241 rendItemDrawer
.InitDrawSubmission();
1243 CRenderView
* pShadowsView
= reinterpret_cast<CRenderView
*>(curPass
.GetFrustum()->pShadowsView
.get());
1245 curPass
.PreRender();
1246 curPass
.BeginExecution(m_graphicsPipeline
);
1247 curPass
.SetupDrawContext(StageID
, curPass
.m_eShadowPassID
, TTYPE_SHADOWGEN
, 0);
1248 curPass
.DrawRenderItems(pShadowsView
, (ERenderListID
)curPass
.m_nShadowFrustumSide
);
1249 curPass
.EndExecution();
1251 rendItemDrawer
.JobifyDrawSubmission();
1252 rendItemDrawer
.WaitForDrawSubmission();
1256 rendItemDrawer
.InitDrawSubmission();
1258 for (auto passGroup
= ePass_DirectionalLight
; passGroup
!= ePass_Count
; passGroup
= EPass(passGroup
+ 1))
1260 if (passGroup
== ePass_DirectionalLightCached
)
1263 for (auto& curPass
: m_ShadowMapPasses
[passGroup
])
1265 if (curPass
.m_bRequiresRender
)
1267 CRenderView
* pShadowsView
= reinterpret_cast<CRenderView
*>(curPass
.GetFrustum()->pShadowsView
.get());
1269 curPass
.PreRender();
1270 curPass
.BeginExecution(m_graphicsPipeline
);
1271 curPass
.SetupDrawContext(StageID
, curPass
.m_eShadowPassID
, TTYPE_SHADOWGEN
, 0);
1272 curPass
.DrawRenderItems(pShadowsView
, (ERenderListID
)curPass
.m_nShadowFrustumSide
);
1273 curPass
.EndExecution();
1278 rendItemDrawer
.JobifyDrawSubmission();