!R (Renderer) Replacing all CryMakeUnique with stl::make_unique
[CRYENGINE.git] / Code / CryEngine / RenderDll / XRenderD3D9 / GraphicsPipeline / ClipVolumes.cpp
blobbc4b1e9dbd2699e9fa130ccecdc0fa92e739978d
1 // Copyright 2001-2015 Crytek GmbH. All rights reserved.
3 #include "StdAfx.h"
4 #include "ClipVolumes.h"
5 #include "DriverD3D.h"
6 #include "VolumetricFog.h"
8 struct SPrimitiveConstants
10 Matrix44 transformMatrix;
11 Vec4 projRatioScreenScale;
12 Vec4 blendPlane0;
13 Vec4 blendPlane1;
16 struct SPrimitiveVolFogConstants
18 Matrix44 transformMatrix;
19 uint32 sliceIndex[4];
22 CClipVolumesStage::CClipVolumesStage()
23 : m_nShaderParamCount(0)
24 , m_pBlendValuesRT(nullptr)
25 , m_pDepthTarget(nullptr)
26 , m_pClipVolumeStencilVolumeTex(nullptr)
27 , m_cleared(MAX_GPU_NUM)
28 , m_nearDepth(-1.0f)
29 , m_raymarchDistance(0.0f)
30 , m_bClipVolumesValid(false)
31 , m_bBlendPassReady(false)
32 , m_bOutdoorVisible(false)
34 ZeroArray(m_clipVolumeShaderParams);
35 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
36 memset(&m_depthTargetVolFog, 0, sizeof(m_depthTargetVolFog));
37 #endif
40 CClipVolumesStage::~CClipVolumesStage()
42 SAFE_RELEASE(m_pClipVolumeStencilVolumeTex);
43 #ifndef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
44 for (auto& pTex : m_pClipVolumeStencilVolumeTexArray)
46 SAFE_RELEASE(pTex);
48 #endif
51 void CClipVolumesStage::Init()
53 m_stencilPass.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass);
54 m_blendValuesPass.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass);
55 m_stencilResolvePass.SetFlags(CPrimitiveRenderPass::ePassFlags_VrProjectionPass);
57 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
58 m_volumetricStencilPass.SetFlags(CPrimitiveRenderPass::ePassFlags_None);
59 #endif
61 for (int i = 0; i < MaxDeferredClipVolumes; ++i)
63 // Stencil pass: two primitives per clip volume, both share the same constant buffer
65 CConstantBufferPtr pCB = gcpRendD3D->m_DevBufMan.CreateConstantBuffer(sizeof(SPrimitiveConstants));
67 m_stencilPrimitives[2 * i + 0].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch, pCB, EShaderStage_Vertex);
68 m_stencilPrimitives[2 * i + 1].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch, pCB, EShaderStage_Vertex);
70 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
71 pCB = gcpRendD3D->m_DevBufMan.CreateConstantBuffer(sizeof(SPrimitiveVolFogConstants));
72 m_stencilPrimitivesVolFog[2 * i + 0].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch, pCB, EShaderStage_Geometry | EShaderStage_Vertex);
73 m_stencilPrimitivesVolFog[2 * i + 1].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch, pCB, EShaderStage_Geometry | EShaderStage_Vertex);
74 #endif
77 // Blend values pass: one primitive per clip volume, shared CB for vertex and pixel shader
79 CConstantBufferPtr pCB = gcpRendD3D->m_DevBufMan.CreateConstantBuffer(sizeof(SPrimitiveConstants));
81 m_blendPrimitives[i].SetInlineConstantBuffer(eConstantBufferShaderSlot_PerBatch, pCB, EShaderStage_Pixel | EShaderStage_Vertex);
86 // TODO: move this texture to intra-view-shared data structure after removing old graphics pipeline.
87 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
88 const uint32 flags = FT_NOMIPS | FT_DONT_STREAM | FT_USAGE_DEPTHSTENCIL;
89 #else
90 const uint32 flags = FT_NOMIPS | FT_DONT_STREAM | FT_USAGE_RENDERTARGET;
91 #endif
92 CRY_ASSERT(m_pClipVolumeStencilVolumeTex == nullptr);
93 m_pClipVolumeStencilVolumeTex = CTexture::GetOrCreateTextureObject("$VolFogClipVolumeStencil", 0, 0, 0, eTT_2D, flags, eTF_Unknown);
96 void CClipVolumesStage::Prepare(CRenderView* pRenderView)
98 m_nShaderParamCount = 0;
99 m_bClipVolumesValid = false;
100 m_bOutdoorVisible = false;
102 m_pBlendValuesRT = CTexture::s_ptexVelocity;
103 m_pDepthTarget = gcpRendD3D->m_pZTexture;
105 D3DViewPort viewport;
106 viewport.TopLeftX = viewport.TopLeftY = 0.0f;
107 viewport.Width = (float)m_pBlendValuesRT->GetWidth();
108 viewport.Height = (float)m_pBlendValuesRT->GetHeight();
109 viewport.MinDepth = 0.0f;
110 viewport.MaxDepth = 1.0f;
112 m_stencilPass.SetDepthTarget(m_pDepthTarget);
113 m_stencilPass.SetViewport(viewport);
114 m_stencilPass.BeginAddingPrimitives();
116 m_blendValuesPass.SetRenderTarget(0, m_pBlendValuesRT);
117 m_blendValuesPass.SetDepthTarget(m_pDepthTarget);
118 m_blendValuesPass.SetViewport(viewport);
119 m_blendValuesPass.BeginAddingPrimitives();
121 PrepareVolumetricFog();
122 if (gcpRendD3D->m_bVolumetricFogEnabled)
124 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
125 m_volumetricStencilPass.BeginAddingPrimitives();
126 #else
127 for (auto& pass : m_volumetricStencilPassArray)
128 pass->BeginAddingPrimitives();
129 #endif
132 const uint32 StencilStateInitialMarkup =
133 STENC_FUNC(FSS_STENCFUNC_GEQUAL) |
134 STENCOP_FAIL(FSS_STENCOP_KEEP) |
135 STENCOP_ZFAIL(FSS_STENCOP_REPLACE) |
136 STENCOP_PASS(FSS_STENCOP_KEEP);
138 const uint32 StencilStateInsideOutsideMarkup =
139 STENC_FUNC(FSS_STENCFUNC_GEQUAL) |
140 STENCOP_FAIL(FSS_STENCOP_KEEP) |
141 STENCOP_ZFAIL(FSS_STENCOP_INVERT) |
142 STENCOP_PASS(FSS_STENCOP_KEEP);
144 const uint32 StencilStateTest =
145 STENC_FUNC(FSS_STENCFUNC_EQUAL) |
146 STENCOP_FAIL(FSS_STENCOP_KEEP) |
147 STENCOP_ZFAIL(FSS_STENCOP_KEEP) |
148 STENCOP_PASS(FSS_STENCOP_KEEP);
150 const uint8 StencilReadWriteMask = 0xFF & ~BIT_STENCIL_RESERVED;
152 static CCryNameTSCRC techStencil = "ClipVolumeStencil";
153 static CCryNameTSCRC techPortalBlend = "ClipVolumeBlendValue";
155 static ICVar* pPortalsBlendCVar = iConsole->GetCVar("e_PortalsBlend");
156 const bool bRenderPortalBlendValues = pPortalsBlendCVar->GetIVal() > 0;
157 const bool bRenderVisAreas = CRenderer::CV_r_VisAreaClipLightsPerPixel > 0;
159 const auto& clipVolumes = pRenderView->GetClipVolumes();
160 CStandardGraphicsPipeline::SViewInfo viewInfo[2];
161 int viewInfoCount = gcpRendD3D->GetGraphicsPipeline().GetViewInfo(viewInfo);
162 const CRenderCamera& rc = *(viewInfo[0].pRenderCamera);
163 const bool bReverseDepth = (viewInfo[0].flags & CStandardGraphicsPipeline::SViewInfo::eFlags_ReverseDepth) != 0;
165 Vec2 projRatio;
166 float zn = rc.fNear;
167 float zf = rc.fFar;
168 projRatio.x = bReverseDepth ? zn / (zn - zf) : zf / (zf - zn);
169 projRatio.y = bReverseDepth ? zn / (zf - zn) : zn / (zn - zf);
171 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
172 static CCryNameTSCRC techStencilVolFog = "ClipVolumeStencilVolFog";
173 const Vec3 cameraFrontVec = rc.vZ;
174 SCGParamsPF& PF = gcpRendD3D->m_cEF.m_PF[gcpRendD3D->m_RP.m_nProcessThreadID];
175 const float raymarchStart = PF.pVolumetricFogSamplingParams.x;
176 const float invRaymarchDistance = PF.pVolumetricFogSamplingParams.y;
177 const int32 volFogDepthNum = CVolumetricFogStage::GetVolumeTextureDepthSize();
178 const float fVolFogDepthNum = static_cast<float>(volFogDepthNum);
179 const int32 maxDepthSliceNum = 64; // this must exactly match to ClipVolumeVolFogGS shader's limitation.
180 #endif
182 m_nShaderParamCount = 0;
183 for (int i = 0; i < VisAreasOutdoorStencilOffset; ++i)
185 uint32 nFlags = IClipVolume::eClipVolumeConnectedToOutdoor | IClipVolume::eClipVolumeAffectedBySun;
186 m_clipVolumeShaderParams[m_nShaderParamCount++] = Vec4(gEnv->p3DEngine->GetSkyColor() * gcpRendD3D->m_fAdaptedSceneScaleLBuffer, alias_cast<float>(nFlags));
189 for (const auto& volume : clipVolumes)
191 // Update shader params
192 const uint32 paramIndex = volume.nStencilRef + 1;
193 CRY_ASSERT(paramIndex >= VisAreasOutdoorStencilOffset);
195 if (paramIndex < MaxDeferredClipVolumes)
197 uint32 nData =
198 (volume.blendInfo[1].blendID + 1) << 24 |
199 (volume.blendInfo[0].blendID + 1) << 16 |
200 volume.nFlags;
202 m_clipVolumeShaderParams[paramIndex] = Vec4(0, 0, 0, alias_cast<float>(nData));
203 m_bOutdoorVisible |= volume.nFlags & IClipVolume::eClipVolumeConnectedToOutdoor ? true : false;
205 m_nShaderParamCount = max(m_nShaderParamCount, paramIndex + 1);
209 // Create stencil and blend pass primitives
210 for (int i = clipVolumes.size() - 1; i >= 0; --i)
212 const SDeferredClipVolume& volume = clipVolumes[i];
213 if (volume.m_pRenderMesh && volume.nStencilRef < MaxDeferredClipVolumes)
215 if ((volume.nFlags & IClipVolume::eClipVolumeIsVisArea) != 0 && !bRenderVisAreas)
216 continue;
218 CRY_ASSERT(((volume.nStencilRef + 1) & (BIT_STENCIL_RESERVED | BIT_STENCIL_INSIDE_CLIPVOLUME)) == 0);
219 const int stencilRef = ~(volume.nStencilRef + 1) & ~(BIT_STENCIL_RESERVED | BIT_STENCIL_INSIDE_CLIPVOLUME);
221 buffer_handle_t hVertexStream = ~0u;
222 buffer_handle_t hIndexStream = ~0u;
223 CRenderMesh* pRenderMesh = nullptr;
225 if (pRenderMesh = reinterpret_cast<CRenderMesh*>(volume.m_pRenderMesh.get()))
227 hVertexStream = pRenderMesh->_GetVBStream(VSF_GENERAL);
228 hIndexStream = pRenderMesh->_GetIBStream();
230 if (hVertexStream != ~0u && hIndexStream != ~0u)
232 // Initial markup
233 CRenderPrimitive& primInit = m_stencilPrimitives[2 * i + 0];
234 primInit.SetTechnique(CShaderMan::s_shDeferredShading, techStencil, 0);
235 primInit.SetRenderState((bReverseDepth ? GS_DEPTHFUNC_GEQUAL : GS_DEPTHFUNC_LEQUAL) | GS_STENCIL);
236 primInit.SetCustomVertexStream(hVertexStream, pRenderMesh->_GetVertexFormat(), pRenderMesh->GetStreamStride(VSF_GENERAL));
237 primInit.SetCustomIndexStream(hIndexStream, (sizeof(vtx_idx) == 2 ? Index16 : Index32));
238 primInit.SetCullMode(eCULL_Front);
239 primInit.SetStencilState(StencilStateInitialMarkup, stencilRef, StencilReadWriteMask, StencilReadWriteMask);
240 primInit.SetDrawInfo(eptTriangleList, 0, 0, pRenderMesh->_GetNumInds());
241 primInit.Compile(m_stencilPass);
243 // Update constant buffer. NOTE: buffer is assigned to preallocated primitives
244 auto& constantManager = primInit.GetConstantManager();
246 auto constants = constantManager.BeginTypedConstantUpdate<SPrimitiveConstants>(eConstantBufferShaderSlot_PerBatch, EShaderStage_Vertex);
247 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[0].cameraProjMatrix;
249 if (viewInfoCount > 1)
251 constants.BeginStereoOverride();
252 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[1].cameraProjMatrix;
255 constantManager.EndTypedConstantUpdate(constants);
257 // Inside/outside test
258 CRenderPrimitive& primMarkup = m_stencilPrimitives[2 * i + 1];
259 primMarkup.SetTechnique(CShaderMan::s_shDeferredShading, techStencil, 0);
260 primMarkup.SetRenderState((bReverseDepth ? GS_DEPTHFUNC_GEQUAL : GS_DEPTHFUNC_LEQUAL) | GS_STENCIL);
261 primMarkup.SetCustomVertexStream(hVertexStream, pRenderMesh->_GetVertexFormat(), pRenderMesh->GetStreamStride(VSF_GENERAL));
262 primMarkup.SetCustomIndexStream(hIndexStream, (sizeof(vtx_idx) == 2 ? Index16 : Index32));
263 primMarkup.SetCullMode(eCULL_None);
264 primMarkup.SetStencilState(StencilStateInsideOutsideMarkup, ~stencilRef, StencilReadWriteMask, StencilReadWriteMask);
265 primMarkup.SetDrawInfo(eptTriangleList, 0, 0, pRenderMesh->_GetNumInds());
266 primMarkup.Compile(m_stencilPass);
268 m_stencilPass.AddPrimitive(&primInit);
269 m_stencilPass.AddPrimitive(&primMarkup);
271 if (gcpRendD3D->m_bVolumetricFogEnabled)
273 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
274 // calculate min depth index of volumetric fog coordinate.
275 const float radius = volume.mAABB.GetRadius();
276 const float distToCenter = -rc.WorldToCamZ(volume.mAABB.GetCenter());
277 const float minW = max(distToCenter - radius, 0.0f);
278 float fMinDepthIndex = fVolFogDepthNum * CVolumetricFogStage::GetDepthTexcoordFromLinearDepthScaled(minW, raymarchStart, invRaymarchDistance, fVolFogDepthNum);
279 fMinDepthIndex = max(0.0f, floorf(fMinDepthIndex));
280 int32 minDepthIndex = static_cast<int32>(fMinDepthIndex);
281 minDepthIndex = max(min(minDepthIndex, volFogDepthNum - 1), 0);
283 // prepare primitive for volumetric fog when it's in the range of volumetric fog.
284 if (minDepthIndex < volFogDepthNum)
286 // Initial markup
287 CRenderPrimitive& primInit = m_stencilPrimitivesVolFog[2 * i + 0];
288 primInit.SetTechnique(CShaderMan::s_shDeferredShading, techStencilVolFog, 0);
289 primInit.SetRenderState((bReverseDepth ? GS_DEPTHFUNC_GEQUAL : GS_DEPTHFUNC_LEQUAL) | GS_STENCIL);
290 primInit.SetCustomVertexStream(hVertexStream, pRenderMesh->_GetVertexFormat(), pRenderMesh->GetStreamStride(VSF_GENERAL));
291 primInit.SetCustomIndexStream(hIndexStream, (sizeof(vtx_idx) == 2 ? Index16 : Index32));
292 primInit.SetCullMode(eCULL_Front);
293 primInit.SetStencilState(StencilStateInitialMarkup, stencilRef, StencilReadWriteMask, StencilReadWriteMask);
294 primInit.SetDrawInfo(eptTriangleList, 0, 0, pRenderMesh->_GetNumInds());
295 primInit.Compile(m_volumetricStencilPass);
297 // Update constant buffer. NOTE: buffer is assigned to preallocated primitives
298 auto& constantManager = primInit.GetConstantManager();
300 auto constants = constantManager.BeginTypedConstantUpdate<SPrimitiveVolFogConstants>(eConstantBufferShaderSlot_PerBatch, EShaderStage_Geometry | EShaderStage_Vertex);
301 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[0].cameraProjMatrix;
303 // calculate max depth index of volumetric fog coordinate.
304 const float maxW = max(distToCenter + radius, 0.0f);
305 float fMaxDepthIndex = fVolFogDepthNum * CVolumetricFogStage::GetDepthTexcoordFromLinearDepthScaled(maxW, raymarchStart, invRaymarchDistance, fVolFogDepthNum);
306 fMaxDepthIndex = max(0.0f, ceilf(fMaxDepthIndex));
307 int32 maxDepthIndex = static_cast<int32>(fMaxDepthIndex);
309 maxDepthIndex = max(maxDepthIndex, 0);
310 maxDepthIndex = min(maxDepthIndex, minDepthIndex + maxDepthSliceNum);
311 maxDepthIndex = min(maxDepthIndex, volFogDepthNum);
313 constants->sliceIndex[0] = minDepthIndex;
314 constants->sliceIndex[1] = maxDepthIndex;
316 if (viewInfoCount > 1)
318 constants.BeginStereoOverride();
319 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[1].cameraProjMatrix;
320 constants->sliceIndex[0] = minDepthIndex;
321 constants->sliceIndex[1] = maxDepthIndex;
324 constantManager.EndTypedConstantUpdate(constants);
326 // Inside/outside test
327 CRenderPrimitive& primMarkup = m_stencilPrimitivesVolFog[2 * i + 1];
328 primMarkup.SetTechnique(CShaderMan::s_shDeferredShading, techStencilVolFog, 0);
329 primMarkup.SetRenderState((bReverseDepth ? GS_DEPTHFUNC_GEQUAL : GS_DEPTHFUNC_LEQUAL) | GS_STENCIL);
330 primMarkup.SetCustomVertexStream(hVertexStream, pRenderMesh->_GetVertexFormat(), pRenderMesh->GetStreamStride(VSF_GENERAL));
331 primMarkup.SetCustomIndexStream(hIndexStream, (sizeof(vtx_idx) == 2 ? Index16 : Index32));
332 primMarkup.SetCullMode(eCULL_None);
333 primMarkup.SetStencilState(StencilStateInsideOutsideMarkup, ~stencilRef, StencilReadWriteMask, StencilReadWriteMask);
334 primMarkup.SetDrawInfo(eptTriangleList, 0, 0, pRenderMesh->_GetNumInds());
335 primMarkup.Compile(m_volumetricStencilPass);
337 m_volumetricStencilPass.AddPrimitive(&primInit);
338 m_volumetricStencilPass.AddPrimitive(&primMarkup);
340 #else
341 for (auto& pass : m_volumetricStencilPassArray)
343 pass->AddPrimitive(&primInit);
344 pass->AddPrimitive(&primMarkup);
346 #endif
351 // Blend values
352 if (bRenderPortalBlendValues && (volume.nFlags & IClipVolume::eClipVolumeBlend))
354 const int stencilTestRef = BIT_STENCIL_INSIDE_CLIPVOLUME + volume.nStencilRef + 1;
356 CRenderPrimitive& primBlend = m_blendPrimitives[i];
357 primBlend.SetTechnique(CShaderMan::s_shDeferredShading, techPortalBlend, CVrProjectionManager::Instance()->GetRTFlags());
358 primBlend.SetRenderState(GS_STENCIL | GS_NODEPTHTEST | GS_NOCOLMASK_R | GS_NOCOLMASK_B | GS_NOCOLMASK_A);
359 primBlend.SetTexture(3, CTexture::s_ptexZTarget);
360 primBlend.SetCullMode(eCULL_Front);
361 primBlend.SetStencilState(StencilStateTest, stencilTestRef, StencilReadWriteMask, StencilReadWriteMask);
362 primBlend.Compile(m_blendValuesPass);
364 auto& constantManager = primBlend.GetConstantManager();
365 auto constants = constantManager.BeginTypedConstantUpdate<SPrimitiveConstants>(eConstantBufferShaderSlot_PerBatch, EShaderStage_Pixel | EShaderStage_Vertex);
367 constants->projRatioScreenScale = Vec4(projRatio.x, projRatio.y, 1.0f / m_pBlendValuesRT->GetWidth(), 1.0f / m_pBlendValuesRT->GetHeight());
368 constants->blendPlane0 = viewInfo[0].invCameraProjMatrix * volume.blendInfo[0].blendPlane;
369 constants->blendPlane1 = viewInfo[0].invCameraProjMatrix * volume.blendInfo[1].blendPlane;
371 if (hVertexStream != ~0u && hIndexStream != ~0u)
373 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[0].cameraProjMatrix;
375 primBlend.SetCustomVertexStream(hVertexStream, pRenderMesh->_GetVertexFormat(), pRenderMesh->GetStreamStride(VSF_GENERAL));
376 primBlend.SetCustomIndexStream(hIndexStream, (sizeof(vtx_idx) == 2 ? Index16 : Index32));
377 primBlend.SetDrawInfo(eptTriangleList, 0, 0, pRenderMesh->_GetNumInds());
379 else
381 constants->transformMatrix = Matrix44(IDENTITY);
383 primBlend.SetPrimitiveType(CRenderPrimitive::ePrim_Triangle);
384 primBlend.SetDrawInfo(eptTriangleList, 0, 0, 3);
387 if (viewInfoCount > 1)
389 constants.BeginStereoOverride();
390 constants->blendPlane0 = viewInfo[1].invCameraProjMatrix * volume.blendInfo[0].blendPlane;
391 constants->blendPlane1 = viewInfo[1].invCameraProjMatrix * volume.blendInfo[1].blendPlane;
393 if (hVertexStream != ~0u && hIndexStream != ~0u)
394 constants->transformMatrix = Matrix44(volume.mWorldTM.GetTransposed()) * viewInfo[1].cameraProjMatrix;
398 constantManager.EndTypedConstantUpdate(constants);
400 m_blendValuesPass.AddPrimitive(&primBlend);
406 void CClipVolumesStage::Execute()
408 PROFILE_LABEL_SCOPE("CLIPVOLUMES");
410 // Render clip volumes to stencil
411 m_stencilPass.Execute();
413 // Render portal blend values
414 m_blendValuesPass.Execute();
416 // Resolve final stencil buffer
418 static CCryNameTSCRC techResolveStencil("ResolveStencil");
420 m_stencilResolvePass.SetPrimitiveFlags(CRenderPrimitive::eFlags_None);
421 m_stencilResolvePass.SetTechnique(CShaderMan::s_shDeferredShading, techResolveStencil, 0);
422 m_stencilResolvePass.SetRenderTarget(0, m_pBlendValuesRT);
423 m_stencilResolvePass.SetState(GS_NODEPTHTEST | GS_NOCOLMASK_G | GS_NOCOLMASK_B | GS_NOCOLMASK_A);
424 m_stencilResolvePass.SetTexture(4, m_pDepthTarget, EDefaultResourceViews::StencilOnly);
425 m_stencilResolvePass.BeginConstantUpdate();
426 m_stencilResolvePass.Execute();
429 ExecuteVolumetricFog();
431 m_bClipVolumesValid = true;
434 CTexture* CClipVolumesStage::GetClipVolumeStencilVolumeTexture() const
436 return m_pClipVolumeStencilVolumeTex;
439 void CClipVolumesStage::PrepareVolumetricFog()
441 if (gcpRendD3D->m_bVolumetricFogEnabled)
443 const int32 screenWidth = gcpRendD3D->GetWidth();
444 const int32 screenHeight = gcpRendD3D->GetHeight();
446 // size for view frustum aligned volume texture.
447 const int32 scaledWidth = CVolumetricFogStage::GetVolumeTextureSize(screenWidth, CRenderer::CV_r_VolumetricFogTexScale);
448 const int32 scaledHeight = CVolumetricFogStage::GetVolumeTextureSize(screenHeight, CRenderer::CV_r_VolumetricFogTexScale);
449 const int32 depth = CVolumetricFogStage::GetVolumeTextureDepthSize();
451 D3DViewPort viewport;
452 viewport.TopLeftX = viewport.TopLeftY = 0.0f;
453 viewport.Width = static_cast<float>(scaledWidth);
454 viewport.Height = static_cast<float>(scaledHeight);
455 viewport.MinDepth = 0.0f;
456 viewport.MaxDepth = 1.0f;
458 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
459 CRY_ASSERT(m_pClipVolumeStencilVolumeTex);
460 if (m_pClipVolumeStencilVolumeTex
461 && (m_pClipVolumeStencilVolumeTex->GetWidth() != scaledWidth
462 || m_pClipVolumeStencilVolumeTex->GetHeight() != scaledHeight
463 || !CTexture::IsTextureExist(m_pClipVolumeStencilVolumeTex))
464 || m_depthTargetArrayVolFog.empty()
465 || m_depthTargetArrayVolFog.size() != depth)
467 m_volumetricStencilPass.SetViewport(viewport);
469 // create jittered depth passes
471 for (int32 i = 0; i < m_jitteredDepthPassArray.size(); ++i)
473 m_jitteredDepthPassArray[i].reset();
476 m_jitteredDepthPassArray.resize(depth);
478 for (int32 i = 0; i < depth; ++i)
480 m_jitteredDepthPassArray[i] = stl::make_unique<CFullscreenPass>();
481 m_jitteredDepthPassArray[i]->SetViewport(viewport);
482 m_jitteredDepthPassArray[i]->SetFlags(CPrimitiveRenderPass::ePassFlags_None);
486 m_depthTargetArrayVolFog.clear();
487 m_depthTargetArrayVolFog.resize(depth);
489 const uint32 commonFlags = FT_NOMIPS | FT_DONT_STREAM | FT_DONT_RELEASE;
490 const uint32 rtFlags = commonFlags | FT_USAGE_RENDERTARGET;
491 const uint32 dsFlags = commonFlags | FT_USAGE_DEPTHSTENCIL;
492 const int32 w = scaledWidth;
493 const int32 h = scaledHeight;
494 const int32 d = depth;
495 ETEX_Format format = eTF_D24S8;
496 CTexture* pTex = CTexture::GetOrCreateTextureArray("$VolFogClipVolumeStencil", w, h, d, 1, eTT_2DArray, dsFlags, format);
498 if (pTex == nullptr
499 || m_pClipVolumeStencilVolumeTex != pTex // texture name must exactly match the name when creating texture object.
500 || pTex->GetFlags() & FT_FAILED)
502 CryFatalError("Couldn't allocate texture.");
505 // DSV to clear stencil buffer.
506 m_depthTargetVolFog = m_pClipVolumeStencilVolumeTex;
508 // separate DSVs to write jittering depth.
509 for (int32 i = 0; i < m_depthTargetArrayVolFog.size(); ++i)
511 SResourceView sliceView = SResourceView::DepthStencilView(DeviceFormats::ConvertFromTexFormat(m_depthTargetVolFog->GetDstFormat()), i, 1, 0);
512 m_depthTargetArrayVolFog[i] = m_depthTargetVolFog->GetDevTexture()->GetOrCreateResourceViewHandle(sliceView); // separate DSV
515 // set depth target before AddPrimitive() is called.
516 m_volumetricStencilPass.SetDepthTarget(m_depthTargetVolFog);
518 // this buffer is managed explicitly on multi GPU.
519 m_pClipVolumeStencilVolumeTex->DisableMgpuSync();
521 // need to clear depth buffer.
522 const int32 safeMargin = 2; // workaround: shader isn't activated in initial several frames.
523 m_cleared = gcpRendD3D->GetActiveGPUCount() + safeMargin;
525 #else
526 CRY_ASSERT(m_pClipVolumeStencilVolumeTex);
527 if (m_pClipVolumeStencilVolumeTex
528 && (m_pClipVolumeStencilVolumeTex->GetWidth() != scaledWidth
529 || m_pClipVolumeStencilVolumeTex->GetHeight() != scaledHeight
530 || !CTexture::IsTextureExist(m_pClipVolumeStencilVolumeTex))
531 || m_depthTargetArrayVolFog.empty()
532 || m_depthTargetArrayVolFog.size() != depth)
534 // create volume stencil passes
536 for (int32 i = 0; i < m_volumetricStencilPassArray.size(); ++i)
538 m_volumetricStencilPassArray[i].reset();
541 m_volumetricStencilPassArray.resize(depth);
543 for (int32 i = 0; i < depth; ++i)
545 m_volumetricStencilPassArray[i] = stl::make_unique<CFullscreenPass>();
546 m_volumetricStencilPassArray[i]->SetViewport(viewport);
547 m_volumetricStencilPassArray[i]->SetFlags(CPrimitiveRenderPass::ePassFlags_None);
551 // create stencil resolve passes
553 for (int32 i = 0; i < m_resolveVolumetricStencilPassArray.size(); ++i)
555 m_resolveVolumetricStencilPassArray[i].reset();
558 m_resolveVolumetricStencilPassArray.resize(depth);
560 for (int32 i = 0; i < depth; ++i)
562 m_resolveVolumetricStencilPassArray[i] = stl::make_unique<CFullscreenPass>();
563 m_resolveVolumetricStencilPassArray[i]->SetViewport(viewport);
564 m_resolveVolumetricStencilPassArray[i]->SetFlags(CPrimitiveRenderPass::ePassFlags_None);
568 // create jittered depth passes
570 for (int32 i = 0; i < m_jitteredDepthPassArray.size(); ++i)
572 m_jitteredDepthPassArray[i].reset();
575 m_jitteredDepthPassArray.resize(depth);
577 for (int32 i = 0; i < depth; ++i)
579 m_jitteredDepthPassArray[i] = stl::make_unique<CFullscreenPass>();
580 m_jitteredDepthPassArray[i]->SetViewport(viewport);
581 m_jitteredDepthPassArray[i]->SetFlags(CPrimitiveRenderPass::ePassFlags_None);
585 const int32 w = scaledWidth;
586 const int32 h = scaledHeight;
587 const int32 d = depth;
589 // create depth stencil textures
591 const uint32 commonFlags = FT_NOMIPS | FT_DONT_STREAM | FT_DONT_RELEASE;
592 const uint32 rtFlags = commonFlags | FT_USAGE_RENDERTARGET;
593 ETEX_Format format = eTF_R8;
595 CTexture* pTex = CTexture::GetOrCreateTextureArray("$VolFogClipVolumeStencil", w, h, d, 1, eTT_2D, rtFlags, format);
597 if (pTex == nullptr
598 || m_pClipVolumeStencilVolumeTex != pTex // texture name must exactly match the name when creating texture object.
599 || pTex->GetFlags() & FT_FAILED)
601 CryFatalError("Couldn't allocate texture.");
604 size_t size = m_pClipVolumeStencilVolumeTexArray.size();
606 for (uint32 i = 0; i < size; ++i)
608 SAFE_RELEASE(m_pClipVolumeStencilVolumeTexArray[i]);
611 m_pClipVolumeStencilVolumeTexArray.resize(depth);
613 const uint32 dsFlags = commonFlags | FT_USAGE_RENDERTARGET | FT_USAGE_DEPTHSTENCIL;
614 ETEX_Format depthFormat = eTF_D24S8;
616 for (uint32 i = 0; i < depth; ++i)
618 CTexture* pTex = new CTexture(dsFlags);
619 if (!(pTex->Create2DTexture(w, h, 1, dsFlags, nullptr, depthFormat)))
621 CryFatalError("Couldn't allocate texture.");
624 m_pClipVolumeStencilVolumeTexArray[i] = pTex;
628 // create depth targets
630 m_depthTargetArrayVolFog.clear();
631 m_depthTargetArrayVolFog.resize(depth);
633 for (int32 i = 0; i < m_depthTargetArrayVolFog.size(); ++i)
635 auto& depthTarget = m_depthTargetArrayVolFog[i];
636 CTexture* pTex = m_pClipVolumeStencilVolumeTexArray[i];
638 // this buffer is managed explicitly on multi GPU.
639 pTex->DisableMgpuSync();
641 // set depth target before AddPrimitive() is called.
642 m_volumetricStencilPassArray[i]->SetDepthTarget(pTex);
646 // need to clear depth buffer.
647 const int32 safeMargin = 2; // workaround: shader isn't activated in initial several frames.
648 m_cleared = gcpRendD3D->GetActiveGPUCount() + safeMargin;
650 #endif
654 void CClipVolumesStage::ExecuteVolumetricFog()
656 CD3D9Renderer* const __restrict rd = gcpRendD3D;
657 SRenderPipeline& rp(rd->m_RP);
658 auto nThreadID = rp.m_nProcessThreadID;
660 if (rd->m_bVolumetricFogEnabled && rp.m_TI[nThreadID].m_FS.m_bEnable)
662 PROFILE_LABEL_SCOPE("CLIPVOLUMES FOR VOLUMETRIC FOG");
664 const bool bReverseDepth = (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) != 0;
665 const float nearDepth = bReverseDepth ? 1.0f : 0.0f;
666 const float raymarchDistance = gRenDev->m_cEF.m_PF[rp.m_nProcessThreadID].pVolumetricFogDistanceParams.w;
668 if (m_nearDepth != nearDepth
669 || (0.25f < abs(m_raymarchDistance - raymarchDistance)))
671 // store values to observe the change.
672 m_nearDepth = nearDepth;
673 m_raymarchDistance = raymarchDistance;
675 // need to clear depth buffer.
676 m_cleared = (m_cleared > 0) ? m_cleared : rd->GetActiveGPUCount();
679 auto maxDSVCount = m_depthTargetArrayVolFog.size();
680 const float fFar = rd->GetRCamera().fFar;
681 const float fNear = rd->GetRCamera().fNear;
682 const float factor0 = fFar / (fFar - fNear);
683 const float factor1 = fNear * -factor0;
684 bool valid = true;
686 #ifdef FEATURE_RENDER_CLIPVOLUME_GEOMETRY_SHADER
687 if (m_cleared > 0)
689 rd->FX_ClearTarget(m_depthTargetVolFog->GetDevTexture()->LookupDSV(EDefaultResourceViews::DepthStencil), CLEAR_STENCIL | CLEAR_ZBUFFER, 0.0f, 0);
691 // write jittering depth.
692 for (int32 i = 0; i < maxDSVCount; ++i)
694 // separate DSV
695 auto& depthTargetView = m_depthTargetArrayVolFog[i];
696 auto& pass = m_jitteredDepthPassArray[i];
698 static CCryNameTSCRC shaderName("StoreJitteringDepthToClipVolumeDepth");
699 pass->SetPrimitiveFlags(CRenderPrimitive::eFlags_ReflectShaderConstants_PS);
700 pass->SetTechnique(CShaderMan::s_shDeferredShading, shaderName, 0);
701 pass->SetState(GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL);
702 pass->SetDepthTarget(m_depthTargetVolFog, depthTargetView);
704 pass->BeginConstantUpdate();
706 static CCryNameR paramDepth("ParamDepth");
707 const Vec4 vParamDepth(static_cast<float>(i), factor1, factor0, nearDepth);
708 pass->SetConstant(paramDepth, vParamDepth, eHWSC_Pixel);
710 bool success = pass->Execute();
712 valid = valid && success;
715 else
717 rd->FX_ClearTarget(m_depthTargetVolFog->GetDevTexture()->LookupDSV(EDefaultResourceViews::DepthStencil), CLEAR_STENCIL, 0.0f, 0);
720 // Render clip volumes to single DSV for depth stencil texture array.
721 m_volumetricStencilPass.Execute();
722 #else
723 if (m_cleared > 0)
725 for (int32 i = 0; i < maxDSVCount; ++i)
727 CTexture* const pTex = m_pClipVolumeStencilVolumeTexArray[i];
728 auto& depthTarget = m_depthTargetArrayVolFog[i];
730 D3DDepthSurface* pDSV = pTex->GetDevTexture()->LookupDSV(depthTarget);
731 rd->FX_ClearTarget(pDSV, CLEAR_STENCIL | CLEAR_ZBUFFER, 0.0f, 0);
733 auto& pass = m_jitteredDepthPassArray[i];
735 // write jittering depth.
736 static CCryNameTSCRC shaderName("StoreJitteringDepthToClipVolumeDepth");
737 pass->SetPrimitiveFlags(CRenderPrimitive::eFlags_ReflectShaderConstants_PS);
738 pass->SetTechnique(CShaderMan::s_shDeferredShading, shaderName, 0);
739 pass->SetState(GS_DEPTHWRITE | GS_DEPTHFUNC_NOTEQUAL);
740 pass->SetDepthTarget(pTex, depthTarget);
742 pass->BeginConstantUpdate();
744 static CCryNameR paramDepth("ParamDepth");
745 const Vec4 vParamDepth(static_cast<float>(i), factor1, factor0, nearDepth);
746 pass->SetConstant(paramDepth, vParamDepth, eHWSC_Pixel);
748 bool success = pass->Execute();
750 valid = valid && success;
753 else
755 for (int32 i = 0; i < maxDSVCount; ++i)
757 CTexture* const pTex = m_pClipVolumeStencilVolumeTexArray[i];
758 auto& depthTarget = m_depthTargetArrayVolFog[i];
760 D3DDepthSurface* pDSV = pTex->GetDevTexture()->LookupDSV(depthTarget);
761 rd->FX_ClearTarget(pDSV, CLEAR_STENCIL, 0.0f, 0);
765 // Render clip volumes.
766 for (int32 i = 0; i < maxDSVCount; ++i)
768 CTexture* const pTex = m_pClipVolumeStencilVolumeTexArray[i];
769 auto& depthTarget = m_depthTargetArrayVolFog[i];
770 auto& pass = m_volumetricStencilPassArray[i];
772 pass->SetDepthTarget(pTex, depthTarget);
773 pass->Execute();
776 // Resolve stencil
777 static CCryNameTSCRC techResolveStencil("ResolveStencilVolFog");
778 for (int32 i = 0; i < maxDSVCount; ++i)
780 auto renderTargetView = SResourceView::RenderTargetView(DeviceFormats::ConvertFromTexFormat(m_pClipVolumeStencilVolumeTex->GetDstFormat()), i, 1, 0, false);
781 ResourceViewHandle rtvHandle = m_pClipVolumeStencilVolumeTex->GetDevTexture()->GetOrCreateResourceViewHandle(renderTargetView);
783 CTexture* const pTex = m_pClipVolumeStencilVolumeTexArray[i];
784 auto stencilOnlyView = SResourceView::ShaderResourceView(DeviceFormats::ConvertFromTexFormat(pTex->GetDstFormat()),
785 0, -1, 0, -1, false, false, SResourceView::eSRV_StencilOnly);
786 ResourceViewHandle srvHandle = pTex->GetDevTexture()->GetOrCreateResourceViewHandle(stencilOnlyView);
788 auto& pPass = m_resolveVolumetricStencilPassArray[i];
789 pPass->SetPrimitiveFlags(CRenderPrimitive::eFlags_None);
790 pPass->SetTechnique(CShaderMan::s_shDeferredShading, techResolveStencil, 0);
791 pPass->SetRenderTarget(0, m_pClipVolumeStencilVolumeTex, rtvHandle);
792 pPass->SetState(GS_NODEPTHTEST);
793 pPass->SetTexture(4, pTex, srvHandle);
794 pPass->BeginConstantUpdate();
795 pPass->Execute();
797 #endif
799 if (valid)
801 m_cleared = (m_cleared > 0) ? (m_cleared - 1) : 0;