You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/RenderDll/XRenderD3D9/D3DDeferredShading.h

528 lines
18 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_XRENDERD3D9_D3DDEFERREDSHADING_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_XRENDERD3D9_D3DDEFERREDSHADING_H
#pragma once
struct IVisArea;
enum EDecalType
{
DTYP_DARKEN,
DTYP_BRIGHTEN,
DTYP_ALPHABLEND,
DTYP_ALPHABLEND_AND_BUMP,
DTYP_ALPHABLEND_SPECULAR,
DTYP_DARKEN_LIGHTBUF,
DTYP_NUM,
};
#define MAX_DEFERRED_CLIP_VOLUMES 64
// Note: 2 stencil values reserved for stencil+outdoor fragments
#define VIS_AREAS_OUTDOOR_STENCIL_OFFSET 2
class CTexPoolAtlas;
struct SShadowAllocData
{
int m_lightID;
uint16 m_blockID;
uint8 m_side;
uint8 m_frameID;
void Clear(){ m_blockID = 0xFFFF; m_lightID = -1; m_frameID = 0; }
bool isFree() { return (m_blockID == 0xFFFF) ? true : false; }
SShadowAllocData(){ Clear(); }
~SShadowAllocData(){ Clear(); }
};
class CDeferredShading
{
public:
static inline bool IsValid()
{
return m_pInstance != NULL;
}
static CDeferredShading& Instance()
{
return (*m_pInstance);
}
void Render();
void SetupPasses();
void SetupGlobalConsts();
// This will setup shadows and sort lights.
// It is called before Z-Pass and is used so that we don't have
// to resolve any buffers because of shadows setup during deferred passes.
void SetupGmemPath();
//shadows
void ResolveCurrentBuffers();
void RestoreCurrentBuffers();
bool PackAllShadowFrustums(TArray<SRenderLight>& arrLights, bool bPreLoop);
void DebugShadowMaskClear();
bool PackToPool(CPowerOf2BlockPacker* pBlockPack, SRenderLight& light, bool bClearPool);
void FilterGBuffer();
void AmbientOcclusionPasses();
void PrepareClipVolumeData(bool& bOutdoorVisible);
void RenderClipVolumesToStencil(int nStencilInsideBit);
void RenderPortalBlendValues(int nStencilInsideBit);
bool AmbientPass(SRenderLight* pGlobalCubemap, bool& bOutdoorVisible);
bool DeferredDecalPass(const SDeferredDecal& rDecal, uint32 indDecal);
void DeferredDecalEmissivePass(const SDeferredDecal& rDecal, uint32 indDecal);
bool ShadowLightPasses(const SRenderLight& light);
void DrawDecalVolume(const SDeferredDecal& rDecal, Matrix44A& mDecalLightProj, ECull volumeCull);
void DrawLightVolume(EShapeMeshType meshType, const Matrix44& mVolumeToWorld, const Vec4& vSphereAdjust = Vec4(ZERO));
void LightPass(const SRenderLight* const __restrict pDL, bool bForceStencilDisable = false);
void DeferredCubemaps(const TArray<SRenderLight>& rCubemaps, const uint32 nStartIndex = 0);
void DeferredCubemapPass(const SRenderLight* const __restrict pDL);
void ScreenSpaceReflectionPass();
void ApplySSReflections();
void DirectionalOcclusionPass();
void HeightMapOcclusionPass(ShadowMapFrustum*& pHeightMapFrustum, CTexture*& pHeightMapAOScreenDepth, CTexture*& pHeightmapAO);
void DeferredLights(TArray<SRenderLight>& rLights, bool bCastShadows);
void DeferredSubsurfaceScattering(CTexture* tmpTex);
void DeferredShadingPass();
void CreateDeferredMaps();
void DestroyDeferredMaps();
void Release();
void Debug();
void DebugGBuffer();
//! Adds a light to the list of lights to be rendered.
//! \param pDL Light to be rendered
//! \param fMult Multiplier that will be applied to the light's intensity. For example, use this to fade out lights as they exceed distance thresholds.
//! \param passInfo Standard SRenderingPassInfo, send to EF_AddEf()
//! \param rendItemSorter Standard SRendItemSorter, send to EF_AddEf()
uint32 AddLight(const CDLight& pDL, float fMult, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter);
inline uint8 AddClipVolume(const IClipVolume* pClipVolume);
inline bool SetClipVolumeBlendData(const IClipVolume* pClipVolume, const SClipVolumeBlendInfo& blendInfo);
inline void ResetLights();
inline void ResetClipVolumes();
// Renderer must be flushed
void ResetAllLights();
void ResetAllClipVolumes();
// called in between levels to free up memory
void ReleaseData();
TArray<SRenderLight>& GetLights(const int nThreadID, const int nCurRecLevel, const eDeferredLightType eType = eDLT_DeferredLight);
SRenderLight* GetLightByID(const uint16 nLightID, const eDeferredLightType eType = eDLT_DeferredLight);
uint32 GetLightsNum(const eDeferredLightType eType);
void GetClipVolumeParams(const Vec4*& pParams, uint32& nCount);
CTexture* GetResolvedStencilRT() { return m_pResolvedStencilRT; }
void GetLightRenderSettings(const SRenderLight* const __restrict pDL, bool& bStencilMask, bool& bUseLightVolumes, EShapeMeshType& meshType);
inline uint32 GetLightsCount() const
{
return m_nLightsProcessedCount;
}
inline Vec4 GetLightDepthBounds(const SRenderLight* pDL, bool bReverseDepth) const
{
float fRadius = pDL->m_fRadius;
if (pDL->m_Flags & DLF_AREA_LIGHT) // Use max for area lights.
{
fRadius += max(pDL->m_fAreaWidth, pDL->m_fAreaHeight);
}
else if (pDL->m_Flags & DLF_DEFERRED_CUBEMAPS)
{
fRadius = pDL->m_ProbeExtents.len(); // This is not optimal for a box
}
return GetLightDepthBounds(pDL->m_Origin, fRadius, bReverseDepth);
}
inline Vec4 GetLightDepthBounds(const Vec3& vCenter, float fRadius, bool bReverseDepth) const
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_DeferredShadingDepthBoundsTest)
{
return Vec4(0.0f, 0.0f, 1.0f, 1.0f);
}
float fMinZ = 0.0f, fMaxZ = 1.0f;
float fMinW = 0.0f, fMaxW = 1.0f;
Vec3 pBounds = m_pCamFront * fRadius;
Vec3 pMax = vCenter - pBounds;
Vec3 pMin = vCenter + pBounds;
fMinZ = m_mViewProj.m20 * pMin.x + m_mViewProj.m21 * pMin.y + m_mViewProj.m22 * pMin.z + m_mViewProj.m23;
fMinW = m_mViewProj.m30 * pMin.x + m_mViewProj.m31 * pMin.y + m_mViewProj.m32 * pMin.z + m_mViewProj.m33;
float fMinDivisor = (float)fsel(-fabsf(fMinW), 1.0f, fMinW);
fMinZ = (float)fsel(-fabsf(fMinW), 1.0f, fMinZ / fMinDivisor);
fMinZ = (float)fsel(fMinW, fMinZ, bReverseDepth ? 1.0f : 0.0f);
fMaxZ = m_mViewProj.m20 * pMax.x + m_mViewProj.m21 * pMax.y + m_mViewProj.m22 * pMax.z + m_mViewProj.m23;
fMaxW = m_mViewProj.m30 * pMax.x + m_mViewProj.m31 * pMax.y + m_mViewProj.m32 * pMax.z + m_mViewProj.m33;
float fMaxDivisor = (float)fsel(-fabsf(fMaxW), 1.0f, fMaxW);
fMaxZ = (float)fsel(-fabsf(fMaxW), 1.0f, fMaxZ / fMaxDivisor);
fMaxZ = (float)fsel(fMaxW, fMaxZ, bReverseDepth ? 1.0f : 0.0f);
if (bReverseDepth)
{
std::swap(fMinZ, fMaxZ);
}
fMinZ = clamp_tpl(fMinZ, 0.000001f, 1.f);
fMaxZ = clamp_tpl(fMaxZ, fMinZ, 1.f);
return Vec4(fMinZ, max(fMinW, 0.000001f), fMaxZ, max(fMaxW, 0.000001f));
}
void GetScissors(const Vec3& vCenter, float fRadius, short& sX, short& sY, short& sWidth, short& sHeight) const;
void SetupScissors(bool bEnable, uint16 x, uint16 y, uint16 w, uint16 h) const;
// Calculate the individual screen-space scissor bounds for all of our bound lights
void CalculateLightScissorBounds();
const Matrix44A& GetCameraProjMatrix() const { return m_mViewProj; }
void SortLigths(TArray<SRenderLight>& ligths) const;
private:
void SetSSDOParameters(const int texSlot);
ITexture* SetTexture(const SShaderItem& sItem, EEfResTextures tex, int slot, const RectF texRect, float surfaceSize, float& mipLevelFactor, int flags);
// Flags used for the above SetTexture function
enum ESetTextureFlags : uint32
{
ESetTexture_Transform = 1 << 0, // Will calculate 2 Vec3s used for transforming tex coords in the shader
ESetTexture_HWSR = 1 << 1, // Will set the HWSR_SAMPLE flag for the specified slot
ESetTexture_bSRGBLookup = 1 << 2, // Value to set on the STexState
ESetTexture_AllowDefault = 1 << 3, // Whether a default texture should be used as backup
ESetTexture_MipFactorProvided = 1 << 4, // Whether to use the mipLevelFactor provide or calculate our own and output it to the same parameter
};
enum
{
// Number of textures available in PostEffectsLib.cfi (_tex0 to _texF)
EMaxTextureSlots = 16,
};
CDeferredShading()
{
m_pShader = 0;
m_pTechName = "DeferredLightPass";
m_pAmbientOutdoorTechName = "AmbientPass";
m_pCubemapsTechName = "DeferredCubemapPass";
m_pCubemapsVolumeTechName = "DeferredCubemapVolumePass";
m_pReflectionTechName = "SSR_Raytrace";
m_pDebugTechName = "Debug";
m_pDeferredDecalTechName = "DeferredDecal";
m_pLightVolumeTechName = "DeferredLightVolume";
m_pParamLightPos = "g_LightPos";
m_pParamLightProjMatrix = "g_mLightProj";
m_pGeneralParams = "g_GeneralParams";
m_pParamLightDiffuse = "g_LightDiffuse";
m_pParamAmbient = "g_cDeferredAmbient";
m_pParamAmbientGround = "g_cAmbGround";
m_pParamAmbientHeight = "g_vAmbHeightParams";
m_pAttenParams = "g_vAttenParams";
m_pParamDecalTS = "g_mDecalTS";
m_pParamDecalDiffuse = "g_DecalDiffuse";
m_pParamDecalAngleAttenuation = "g_DecalAngleAttenuation";
m_pParamDecalSpecular = "g_DecalSpecular";
m_pParamDecalMipLevels = "g_DecalMipLevels";
m_pParamDecalEmissive = "g_DecalEmissive";
m_pParamTexTransforms = "g_texTransforms";
m_pClipVolumeParams = "g_vVisAreasParams";
m_pLBufferDiffuseRT = CTexture::s_ptexCurrentSceneDiffuseAccMap;
m_pLBufferSpecularRT = CTexture::s_ptexSceneSpecularAccMap;
m_pNormalsRT = CTexture::s_ptexSceneNormalsMap;
m_pDepthRT = CTexture::s_ptexZTarget;
m_pMSAAMaskRT = CTexture::s_ptexBackBuffer;
m_pResolvedStencilRT = CTexture::s_ptexStereoR;
m_pDiffuseRT = CTexture::s_ptexSceneDiffuse;
m_pSpecularRT = CTexture::s_ptexSceneSpecular;
memset(m_vClipVolumeParams, 0, sizeof(Vec4) * (MAX_DEFERRED_CLIP_VOLUMES));
m_nLightsProcessedCount = 0;
m_nCurLighID = -1;
m_nWarningFrame = 0;
m_bSpecularState = false;
m_nShadowPoolSize = 0;
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
// render to texture supports multiple cameras
const AZ::EntityId defaultEntityId;
Matrix44 identityMatrix;
identityMatrix.SetIdentity();
for (int i = 0; i < MAX_GPU_NUM; ++i)
{
m_prevViewProj[i].insert({ defaultEntityId, identityMatrix });
}
#else
for (int i = 0; i < MAX_GPU_NUM; ++i)
{
m_prevViewProj[i].SetIdentity();
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
m_nRenderState = GS_BLSRC_ONE | GS_BLDST_ONE;
m_nTexStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
m_nTexStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
m_nThreadID = 0;
m_nRecurseLevel = 0;
m_nBindResourceMsaa = -1;
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
for (int j = 0; j < MAX_REND_RECURSION_LEVELS; ++j)
{
m_nClipVolumesCount[i][j] = 0;
m_nVisAreasGIRef[i][j] = 0;
}
}
}
~CDeferredShading()
{
Release();
}
// Allow disable mrt usage: for double zspeed and on other passes less fillrate hit
// @return - Returns true if either a push or a pop was performed in this function. Returns false if no push or pop was executed.
bool SpecularAccEnableMRT(bool bEnable);
private:
struct SVisAreaBlendData
{
uint8 nBlendIDs[SClipVolumeBlendInfo::BlendPlaneCount];
Vec4 blendPlanes[SClipVolumeBlendInfo::BlendPlaneCount];
};
struct SClipVolumeData
{
SClipVolumeData()
: nStencilRef(0)
, nFlags(0)
, m_pRenderMesh(NULL)
, mAABB(AABB::RESET)
, mWorldTM(IDENTITY)
{
};
Matrix34 mWorldTM;
AABB mAABB;
uint8 nStencilRef;
uint8 nFlags;
_smart_ptr<IRenderMesh> m_pRenderMesh;
SVisAreaBlendData m_BlendData;
};
// Vis areas for current view
std::vector<SClipVolumeData> m_pClipVolumes[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
// The 2 is for X and Y axis. In PostEffectsLib.cfi:
// float2x4 g_texTransforms[16];
Vec4 m_vTextureTransforms[EMaxTextureSlots][2];
uint32 m_nClipVolumesCount[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
uint32 m_nVisAreasGIRef[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
struct SClipShape
{
IRenderMesh* pShape;
Matrix34 mxTransform;
SClipShape()
: pShape(NULL)
, mxTransform(Matrix34::CreateIdentity()) {}
SClipShape(IRenderMesh* _pShape, const Matrix34& _mxTransform)
: pShape(_pShape)
, mxTransform(_mxTransform) { }
};
// Clip volumes for GI for current view
TArray<SClipShape> m_vecGIClipVolumes[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
// Deferred passes common
TArray<SRenderLight> m_pLights[eDLT_NumLightTypes][RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
Vec3 m_pCamPos;
Vec3 m_pCamFront;
float m_fCamFar;
float m_fCamNear;
float m_fRatioWidth;
float m_fRatioHeight;
CShader* m_pShader;
CCryNameTSCRC m_pDeferredDecalTechName;
CCryNameTSCRC m_pLightVolumeTechName;
CCryNameTSCRC m_pTechName;
CCryNameTSCRC m_pAmbientOutdoorTechName;
CCryNameTSCRC m_pCubemapsTechName;
CCryNameTSCRC m_pCubemapsVolumeTechName;
CCryNameTSCRC m_pReflectionTechName;
CCryNameTSCRC m_pDebugTechName;
CCryNameR m_pParamLightPos;
CCryNameR m_pParamLightDiffuse;
CCryNameR m_pParamLightProjMatrix;
CCryNameR m_pGeneralParams;
CCryNameR m_pParamAmbient;
CCryNameR m_pParamAmbientGround;
CCryNameR m_pParamAmbientHeight;
CCryNameR m_pAttenParams;
CCryNameR m_pParamDecalTS;
CCryNameR m_pParamDecalDiffuse;
CCryNameR m_pParamDecalAngleAttenuation;
CCryNameR m_pParamDecalSpecular;
CCryNameR m_pParamDecalMipLevels;
CCryNameR m_pParamDecalEmissive;
CCryNameR m_pParamTexTransforms;
CCryNameR m_pClipVolumeParams;
Matrix44A m_mViewProj;
Matrix44A m_pViewProjI;
Matrix44A m_pView;
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
// render to texture supports multiple cameras
// we do not use Matrix44A here because this is used with Matrix44s and will
// fail to compile in release mode due to alignment errors
AZStd::unordered_map<AZ::EntityId, Matrix44> m_prevViewProj[MAX_GPU_NUM];
#else
Matrix44A m_prevViewProj[MAX_GPU_NUM];
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
Vec4 vWorldBasisX, vWorldBasisY, vWorldBasisZ;
CTexture* m_pLBufferDiffuseRT;
CTexture* m_pLBufferSpecularRT;
DEFINE_ALIGNED_DATA(Vec4, m_vClipVolumeParams[MAX_DEFERRED_CLIP_VOLUMES], 16);
CTexture* m_pDiffuseRT;
CTexture* m_pSpecularRT;
CTexture* m_pNormalsRT;
CTexture* m_pDepthRT;
CTexture* m_pMSAAMaskRT;
CTexture* m_pResolvedStencilRT;
int m_nWarningFrame;
int m_nRenderState;
uint32 m_nLightsProcessedCount;
uint32 m_nTexStateLinear;
uint32 m_nTexStatePoint;
SResourceView::KeyType m_nBindResourceMsaa;
uint32 m_nThreadID;
int32 m_nRecurseLevel;
uint m_nCurrentShadowPoolLight;
uint m_nFirstCandidateShadowPoolLight;
uint m_nShadowPoolSize;
bool m_bClearPool;
bool m_bSpecularState;
int m_nCurLighID;
short m_nCurTargetWidth;
short m_nCurTargetHeight;
static CDeferredShading* m_pInstance;
friend class CTiledShading;
static StaticInstance<CPowerOf2BlockPacker> m_blockPack;
static TArray<SShadowAllocData> m_shadowPoolAlloc;
public:
static CDeferredShading* CreateDeferredShading()
{
m_pInstance = new CDeferredShading();
return m_pInstance;
}
static void DestroyDeferredShading()
{
SAFE_DELETE(m_pInstance);
}
};
class CTexPoolAtlas
{
public:
CTexPoolAtlas()
{
m_nSize = 0;
#ifdef _DEBUG
m_nTotalWaste = 0;
#endif
}
~CTexPoolAtlas() {}
void Init(int nSize);
void Clear();
void FreeMemory();
bool AllocateGroup(int32* pOffsetX, int32* pOffsetY, int nSizeX, int nSizeY);
int m_nSize;
static const int MAX_BLOCKS = 128;
uint32 m_arrAllocatedBlocks[MAX_BLOCKS];
#ifdef _DEBUG
uint32 m_nTotalWaste;
struct SShadowMapBlock
{
uint16 m_nX1, m_nX2, m_nY1, m_nY2;
bool Intersects(const SShadowMapBlock& b) const
{
return max(m_nX1, b.m_nX1) < min(m_nX2, b.m_nX2)
&& max(m_nY1, b.m_nY1) < min(m_nY2, b.m_nY2);
}
};
std::vector<SShadowMapBlock> m_arrDebugBlocks;
void _AddDebugBlock(int x, int y, int sizeX, int sizeY);
float _GetDebugUsage() const;
#endif
};
#endif