!B (CE-20767) Enabled opaque rendering and shadows for GPU particles. Added ZPassGPU...
[CRYENGINE.git] / Code / CryEngine / RenderDll / XRenderD3D9 / GraphicsPipeline / ShadowMap.cpp
blob8a2b2c4494571e287b0d307e3f8d7582c26879a8
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include <CryMath/Range.h>
5 #include "ShadowMap.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)
18 #include "D3D_SVO.h"
19 #endif
21 // *INDENT-OFF*
22 ETEX_Format CShadowMapStage::GetShadowTexFormat(const SShadowConfig& shadowConfig, EPass passID) const
24 switch(passID)
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);
42 return eTF_Unknown;
44 // *INDENT-ON*
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);
82 // particle resources
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();
105 else
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));
153 #endif
155 // preallocate typically used passes (NOTE: at least one pass is needed for PSO compilation)
156 // *INDENT-OFF*
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);
162 // *INDENT-ON*
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
182 ++reallocationCount;
183 #endif
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];
200 if (!pTx)
202 char szName[64];
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();
301 size_t sizeSum = 0;
302 for (auto stat : textureSet)
303 sizeSum += stat.second;
304 return sizeSum;
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();
344 else
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;
357 if (!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)
373 outPSO = NULL;
375 CShader* pShader = static_cast<CShader*>(description.shaderItem.m_pShader);
376 SShaderTechnique* pTechnique = pShader->GetTechnique(description.shaderItem.m_nTechnique, description.technique, true);
377 if (!pTechnique)
378 return true;
380 CShaderResources* pRes = static_cast<CShaderResources*>(description.shaderItem.m_pShaderResources);
381 if (pRes->m_ResFlags & MTL_FLAG_NOSHADOW)
382 return true;
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 )
398 // {
399 // SStateRaster customRS = curRS;
400 // customRS.Desc.DepthClipEnable = false;
401 // rd->SetRasterState(&customRS);
402 // }
405 // Set resource states
406 bool bTwoSided = false;
408 if (pRes->m_ResFlags & MTL_FLAG_2SIDED)
409 bTwoSided = true;
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];
430 //tessellation
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;
441 #endif
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;
449 else
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];
462 // RBPF_MIRRORCULL
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];
514 #endif
516 // Create PSO
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))
526 return true;
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]);
536 if (bFullyCompiled)
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)
563 passGroup.Reset();
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;
591 EPass passID;
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());
629 else
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);
649 else
651 passID = ePass_LocalLightRSM;
652 cry_sprintf(profileLabel, "LOCAL LIGHT (RSM) %s", frustumToRender.pLight->m_sName);
655 else
656 #endif
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);
666 break;
667 case CRenderView::eShadowFrustumRenderType_SunCached:
669 passID = ePass_DirectionalLightCached;
670 cry_sprintf(profileLabel, "SUN CACHED %i", frustum.nShadowMapLod);
672 break;
673 case CRenderView::eShadowFrustumRenderType_HeightmapAO:
675 passID = ePass_DirectionalLightCached;
676 cry_sprintf(profileLabel, "HEIGHTMAP AO");
678 break;
679 case CRenderView::eShadowFrustumRenderType_Custom:
681 passID = ePass_DirectionalLight;
683 if (frustum.m_eFrustumType == ShadowMapFrustum::e_Nearest)
685 cry_sprintf(profileLabel, "SUN NEAREST");
687 else
689 cry_sprintf(profileLabel, "SUN PER OBJECT");
692 break;
693 case CRenderView::eShadowFrustumRenderType_LocalLight:
695 passID = ePass_LocalLight;
696 cry_sprintf(profileLabel, "LOCAL LIGHT %s", frustumToRender.pLight->m_sName);
698 break;
703 bool CShadowMapStage::PrepareOutputsForPass(const SShadowFrustumToRender& frustumToRender, int nSide, CShadowMapPass& targetPass) const
705 const ShadowMapFrustum& frustum = *frustumToRender.pFrustum;
707 int arrViewport[4];
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);
722 else
724 char pName[256];
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);
738 else
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);
751 #endif
753 targetPass.m_pDepthTarget = pDepthTarget;
754 if (!pDepthTarget || !pDepthTarget->GetDevTexture())
755 return false;
757 // now apply to pass
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);
765 return true;
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);
845 break;
850 return pDepthTarget;
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;
874 aabb.Move(camPos);
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);
895 else
897 Matrix44 view, proj;
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)
912 m_Passes.clear();
913 m_Passes.reserve(nSize);
914 m_PassCount = 0;
915 m_pStage = pStage;
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();
983 if (pTerrain)
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);
1001 // per pass CB
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();
1017 #endif
1019 cb.CopyToDevice();
1021 m_perPassResources.SetConstantBuffer(eConstantBufferShaderSlot_PerPass, m_pPerPassConstantBuffer.get(), EShaderStage_Vertex | EShaderStage_Hull | EShaderStage_Domain | EShaderStage_Pixel);
1024 // per view CB
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);
1089 else
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) };
1115 else
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();
1123 Vec4 crop = Vec4(
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)
1170 continue;
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());
1197 #endif
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)
1218 break;
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)
1261 continue;
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();