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/Common/PostProcess/PostProcess.h

737 lines
20 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 _POSTPROCESS_H_
#define _POSTPROCESS_H_
class CShader;
class CTexture;
// Declare effects ID - this will also be used as rendering sort order
enum EPostEffectID
{
ePFX_Invalid = -1,
ePFX_WaterVolume = 0,
ePFX_WaterRipples,
ePFX_SceneRain,
// Don't change order of post processes before sunshafts (on pc we doing some trickery to avoid redundant stretchrects)
ePFX_SunShafts,
ePFX_eMotionBlur,
ePFX_ColorGrading,
ePFX_eDepthOfField,
ePFX_HUDSilhouettes,
ePFX_eSoftAlphaTest,
ePFX_PostAA,
ePFX_SceneSnow,
ePFX_eUnderwaterGodRays,
ePFX_eVolumetricScattering,
// todo: merge all following into UberGamePostProcess
ePFX_FilterSharpening,
ePFX_FilterBlurring,
ePFX_UberGamePostProcess,
ePFX_eFlashBang,
ePFX_ImageGhosting,
ePFX_eRainDrops,
ePFX_eWaterDroplets,
ePFX_eWaterFlow,
ePFX_eScreenBlood,
ePFX_eScreenFrost,
ePFX_FilterKillCamera,
ePFX_eAlienInterference,
ePFX_eGhostVision,
ePFX_Post3DRenderer,
ePFX_ScreenFader,
ePFX_Max
};
// Base effect parameter class, derive all new from this one
class CEffectParam
{
public:
CEffectParam(){ }
virtual ~CEffectParam()
{
Release();
}
// Should implement where necessary. For example check CParamTexture
virtual void Release() { }
// Set parameters
virtual void SetParam([[maybe_unused]] float fParam, [[maybe_unused]] bool bForceValue = false) {}
virtual void SetParamVec4([[maybe_unused]] const Vec4& pParam, [[maybe_unused]] bool bForceValue = false) {}
virtual void SetParamString([[maybe_unused]] const char* pszParam) {}
virtual void ResetParam(float fParam) { SetParam(fParam, true); }
virtual void ResetParamVec4(const Vec4& pParam) { SetParamVec4(pParam, true); }
// Get parameters
virtual float GetParam() { return 1.0f; }
virtual Vec4 GetParamVec4() { return Vec4(1.0f, 1.0f, 1.0f, 1.0f); }
virtual const char* GetParamString() const { return 0; }
// Sync main thread data with render thread data
virtual void SyncMainWithRender() {}
// Create effect parameter
template <typename ParamT, typename T>
static CEffectParam* Create(const T& pParam, bool bSmoothTransition = true)
{
return new ParamT(pParam, bSmoothTransition);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Bool type effect param
class CParamBool
: public CEffectParam
{
public:
CParamBool(bool bParam, [[maybe_unused]] bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamBoolThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->bParam = bParam;
pThreadSafeData->bSetThisFrame = false;
}
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamBoolThreadSafeData
{
bool bParam;
bool bSetThisFrame;
};
CParamBoolThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Int type effect param
class CParamInt
: public CEffectParam
{
public:
CParamInt(int nParam, [[maybe_unused]] bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamIntThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->nParam = nParam;
pThreadSafeData->bSetThisFrame = false;
}
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamIntThreadSafeData
{
int nParam;
bool bSetThisFrame;
};
CParamIntThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Float type effect param
class CParamFloat
: public CEffectParam
{
public:
CParamFloat(float fParam, bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamFloatThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->fParam = fParam;
pThreadSafeData->fFrameParamAcc = fParam;
pThreadSafeData->nFrameSetCount = 0;
pThreadSafeData->bValueForced = false;
}
m_fParamDefault = fParam;
m_bSmoothTransition = bSmoothTransition;
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamFloatThreadSafeData
{
float fParam;
float fFrameParamAcc;
uint8 nFrameSetCount;
bool bValueForced;
bool bSetThisFrame;
};
CParamFloatThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
float m_fParamDefault;
bool m_bSmoothTransition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Vec4 type effect param
class CParamVec4
: public CEffectParam
{
public:
CParamVec4(const Vec4& vParam, bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamVec4ThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->vParam = vParam;
pThreadSafeData->vFrameParamAcc = vParam;
pThreadSafeData->nFrameSetCount = 0;
pThreadSafeData->bValueForced = false;
}
m_vParamDefault = vParam;
m_bSmoothTransition = bSmoothTransition;
}
virtual void SetParamVec4(const Vec4& vParam, bool bForceValue);
virtual Vec4 GetParamVec4();
virtual void SyncMainWithRender();
private:
struct CParamVec4ThreadSafeData
{
Vec4 vParam;
Vec4 vFrameParamAcc;
uint8 nFrameSetCount;
bool bValueForced;
bool bSetThisFrame;
};
CParamVec4ThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
Vec4 m_vParamDefault;
bool m_bSmoothTransition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// CTexture type effect param
class CParamTexture
: public CEffectParam
{
public:
CParamTexture()
{
Reset();
}
CParamTexture([[maybe_unused]] int nInit, [[maybe_unused]] bool bSmoothTransition)
{
Reset();
}
virtual ~CParamTexture()
{
Release();
}
int Create(const char* pszFileName);
virtual void Release();
virtual void SetParamString(const char* pParam)
{
Create(pParam);
}
virtual const char* GetParamString() const;
CTexture* GetParamTexture() const
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return m_threadSafeData[threadID].pTexParam;
}
virtual void SyncMainWithRender();
private:
void Reset()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamTextureThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->pTexParam = NULL;
pThreadSafeData->bSetThisFrame = false;
}
}
struct CParamTextureThreadSafeData
{
CTexture* pTexParam;
bool bSetThisFrame;
};
CParamTextureThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Post processing render flags
enum EPostProcessRenderFlag
{
PSP_UPDATE_BACKBUFFER = (1 << 0), // updates back-buffer texture for technique
PSP_REQUIRES_UPDATE = (1 << 1), // required calling update member function
PSP_LAST_ENABLED_POSTPROCESS = (1 << 2), // last enabled post process (used to determine if rendering directly to backbuffer required)
PSP_UPDATE_SCENE_SPECULAR = (1 << 3) // updates/overwrites the scene specular texture (s_ptexSceneSpecular) for use in the current effect
};
// Post effects base structure interface. All techniques derive from this one.
class CPostEffect
{
public:
CPostEffect()
: m_pActive(0)
, /*m_nID(ePFX_DefaultID),*/ m_nRenderFlags(PSP_UPDATE_BACKBUFFER)
{
}
virtual ~CPostEffect()
{
Release();
}
// Initialize post processing technique - device access allowed (queries, ...)
virtual int Initialize() { return 1; }
// Create all the resources for the pp effects which don't require the device (such as textures)
virtual int CreateResources() { return 1; }
// Free resources used
virtual void Release() { }
// Preprocess technique
virtual bool Preprocess() { return IsActive(); }
// Some effects might require updating data/parameters, etc
virtual void Update() { };
// Render technique
virtual void Render() = 0;
// Reset technique state to default
virtual void Reset(bool bOnSpecChange = false) = 0;
// release resources when required
virtual void OnLostDevice() { }
// Add render element/object to post process (use for custom geometry)
virtual void AddRE([[maybe_unused]] const CRendElementBase* pRE, [[maybe_unused]] const SShaderItem* pShaderItem, [[maybe_unused]] CRenderObject* pObj, [[maybe_unused]] const SRenderingPassInfo& passInfo) { }
// release resources when required
virtual void OnBeginFrame() { }
// Get technique render flags
int GetRenderFlags() const
{
return m_nRenderFlags;
}
// Get effect name
virtual const char* GetName() const
{
return "PostEffectDefault";
}
// Is technique active ?
virtual bool IsActive() const
{
float fActive = m_pActive->GetParam();
return (fActive) ? 1 : 0;
}
inline uint8 GetID() const
{
return m_nID;
}
protected:
uint8 m_nRenderFlags;
uint8 m_nID;
CEffectParam* m_pActive;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
typedef std::map<string, CEffectParam*> StringEffectMap;
typedef StringEffectMap::iterator StringEffectMapItor;
typedef std::map<uint32, CEffectParam*> KeyEffectMap;
typedef KeyEffectMap::iterator KeyEffectMapItor;
typedef std::vector< CPostEffect* > CPostEffectVec;
typedef CPostEffectVec::iterator CPostEffectItor;
# ifndef _RELEASE
#define POSTSEFFECTS_DEBUGINFO_TIMEOUT (1.0f)
struct SPostEffectsDebugInfo
{
SPostEffectsDebugInfo(CPostEffect* _pEffect)
: pEffect(_pEffect)
, szParamName(NULL)
, fParamVal(0.0f)
, fTimeOut(POSTSEFFECTS_DEBUGINFO_TIMEOUT){}
SPostEffectsDebugInfo(const string& _szParamName, float val)
: pEffect(NULL)
, szParamName(_szParamName)
, fParamVal(val)
, fTimeOut(POSTSEFFECTS_DEBUGINFO_TIMEOUT){}
CPostEffect* pEffect;
string szParamName;
float fParamVal;
float fTimeOut;
};
typedef std::vector< SPostEffectsDebugInfo > CPostEffectDebugVec;
#endif
class CPostEffectsMgr;
CPostEffectsMgr* PostEffectMgr();
// Post process effects manager
class CPostEffectsMgr
{
public:
CPostEffectsMgr()
: m_nPostBlendEffectsFlags(0)
{
ClearCache();
#ifndef _RELEASE
m_activeEffectsDebug.reserve(16);
m_activeParamsDebug.reserve(32);
#endif
m_bCreated = false;
}
virtual ~CPostEffectsMgr()
{
Release();
}
// Create/Initialize post processing effects
int Init();
void CreateResources();
// Free resources used
void Release();
void ReleaseResources();
// Reset all post effects
void Reset(bool bOnSpecChange = false);
// Start processing effects
void Begin();
// End processing effects
void End();
// release resources when required
void OnLostDevice();
// release resources when required
void OnBeginFrame();
// Sync main thread post effect data with render thread post effect data
void SyncMainWithRender();
// Get techniques list
CPostEffectVec& GetEffects()
{
return m_pEffects;
}
inline bool IsCreated()
{
return m_pEffects.size() != 0;
}
// Get post effect
CPostEffect* GetEffect(EPostEffectID nID)
{
assert(nID < ePFX_Max);
return m_pEffects[ nID ];
}
// Get post effect ID
int32 GetEffectID(const char* pEffectName);
// Get name to id map
KeyEffectMap& GetNameIdMap()
{
return m_pNameIdMap;
}
// Given a string returns corresponding SEffectParam if exists, else returns null
CEffectParam* GetByName(const char* pszParam);
// Given a string returns containing value if exists, else returns 0
float GetByNameF(const char* pszParam);
Vec4 GetByNameVec4(const char* pszParam);
// Register effect
void RegisterEffect(CPostEffect* pEffect)
{
assert(pEffect);
m_pEffects.push_back(pEffect);
}
// Register a parameter
template <typename paramT, typename T>
void RegisterParam(const char* pszName, CEffectParam*& pParam, const T& pParamVal, bool bSmoothTransition = true)
{
pParam = CEffectParam::Create< paramT >(pParamVal, bSmoothTransition);
m_pNameIdMapGen.insert(StringEffectMapItor::value_type(pszName, pParam));
}
// Current enabled post blending effects
uint8 GetPostBlendEffectsFlags()
{
return m_nPostBlendEffectsFlags;
}
// Enabled/disable post blending effects
void SetPostBlendEffectsFlags(uint8 nFlags)
{
m_nPostBlendEffectsFlags = nFlags;
}
friend CPostEffectsMgr* PostEffectMgr();
static bool CheckPostProcessQuality(ERenderQuality nMinRQ, EShaderQuality nMinSQ)
{
if (gRenDev->m_RP.m_eQuality >= nMinRQ && gRenDev->EF_GetShaderQuality(eST_PostProcess) >= nMinSQ)
{
return true;
}
return false;
}
StringEffectMap* GetDebugParamsUsedInFrame()
{
return &m_pEffectParamsUpdated;
}
#ifndef _RELEASE
CPostEffectDebugVec& GetActiveEffectsDebug() { return m_activeEffectsDebug; }
CPostEffectDebugVec& GetActiveEffectsParamsDebug() { return m_activeParamsDebug; }
void ClearDebugInfo()
{
m_activeEffectsDebug.clear();
m_activeParamsDebug.clear();
}
#endif
static int SortEffectsByID(const CPostEffect* p1, const CPostEffect* p2);
// Get techniques list
CPostEffectVec& GetActiveEffects(int threadID)
{
return m_activeEffects[threadID];
}
private:
// Pass a text string to this function and it will return the CRC
uint32 GetCRC(const char* pszName);
// Used only when creating the crc table
uint32 CRC32Reflect(uint32 ref, char ch);
// zero out the cache
void ClearCache()
{
#ifndef _RELEASE
ClearDebugInfo();
#endif
for (int i = 0; i < RT_COMMAND_BUF_COUNT; i++)
{
m_pParamCache[i].m_nKey = 0;
m_pParamCache[i].m_pParam = 0;
}
}
protected:
bool m_bPostReset;
bool m_bCreated;
uint8 m_nPostBlendEffectsFlags;
// Shared parameters
CEffectParam* m_pBrightness, * m_pContrast, * m_pSaturation, * m_pSharpening;
CEffectParam* m_pColorC, * m_pColorY, * m_pColorM, * m_pColorK, * m_pColorHue;
CEffectParam* m_pUserBrightness, * m_pUserContrast, * m_pUserSaturation, * m_pUserSharpening;
CEffectParam* m_pUserColorC, * m_pUserColorY, * m_pUserColorM, * m_pUserColorK, * m_pUserColorHue;
// sorry: quick & dirty solution for c2 shipping - custom type handling for HDR setup in cinematics - make this properly after shipping
CEffectParam* m_UserHDRBloom;
CPostEffectVec m_pEffects;
CPostEffectVec m_activeEffects[RT_COMMAND_BUF_COUNT];
KeyEffectMap m_pNameIdMap;
StringEffectMap m_pNameIdMapGen;
// for debugging purposes only
StringEffectMap m_pEffectParamsUpdated;
#ifndef _RELEASE
CPostEffectDebugVec m_activeEffectsDebug;
CPostEffectDebugVec m_activeParamsDebug;
#endif
uint32 m_nCRC32Table[256]; // Lookup table array
struct ParamCache
{
uint32 m_nKey;
CEffectParam* m_pParam;
} m_pParamCache[RT_COMMAND_BUF_COUNT];
};
//////////////////////////////////////////////////////////////////////////////////////////////////
// Some nice utilities for handling post effects containers
//////////////////////////////////////////////////////////////////////////////////////////////////
#define AddEffect(ef) PostEffectMgr()->RegisterEffect(CryAlignedNew<ef>())
#define AddParamBool(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamBool, bool>((szName), (pParam), val)
#define AddParamInt(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamInt, int>((szName), (pParam), val)
#define AddParamFloat(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamFloat, float>((szName), (pParam), val)
#define AddParamVec4(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamVec4, Vec4>((szName), (pParam), val)
#define AddParamFloatNoTransition(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamFloat, float>((szName), (pParam), val, false)
#define AddParamVec4NoTransition(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamVec4, Vec4>((szName), (pParam), val, false)
#define AddParamTex(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamTexture, int>((szName), (pParam), val)
struct container_object_safe_delete
{
template<typename T>
void operator()(T* pObj) const
{
CryAlignedDelete(pObj);
}
};
struct container_object_safe_release
{
template<typename T>
void operator()(T* pObj) const
{
SAFE_RELEASE(pObj);
}
};
struct SContainerKeyEffectParamDelete
{
void operator()(KeyEffectMap::value_type& pObj)
{
SAFE_DELETE(pObj.second);
}
};
struct SContainerPostEffectInitialize
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->Initialize();
}
}
};
struct SContainerPostEffectCreateResources
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->CreateResources();
}
}
};
struct SContainerPostEffectReset
{
void operator()(CPostEffect* pObj) const
{
if (pObj)
{
pObj->Reset();
}
}
};
struct SContainerPostEffectResetOnSpecChange
{
void operator()(CPostEffect* pObj) const
{
if (pObj)
{
pObj->Reset(true);
}
}
};
struct SContainerPostEffectOnLostDevice
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->OnLostDevice();
}
}
};
struct SContainerPostEffectOnBeginFrame
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->OnBeginFrame();
}
}
};
#endif