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/PostProcessUtils.cpp

689 lines
29 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.
// Description : Post processing common utilities
#include "RenderDll_precompiled.h"
#include "PostProcessUtils.h"
#include "../RendElements/FlareSoftOcclusionQuery.h"
RECT SPostEffectsUtils::m_pScreenRect;
ITimer* SPostEffectsUtils::m_pTimer;
int SPostEffectsUtils::m_iFrameCounter = 0;
SDepthTexture* SPostEffectsUtils::m_pCurDepthSurface;
CShader* SPostEffectsUtils::m_pCurrShader;
int SPostEffectsUtils::m_nColorMatrixFrameID;
float SPostEffectsUtils::m_fWaterLevel;
float SPostEffectsUtils::m_fOverscanBorderAspectRatio = 1.0f;
Matrix44 SPostEffectsUtils::m_pScaleBias = Matrix44(
0.5f, 0, 0, 0,
0, -0.5f, 0, 0,
0, 0, 1.0f, 0,
0.5f, 0.5f, 0, 1.0f);
Vec3 SPostEffectsUtils::m_vRT = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vLT = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vLB = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vRB = Vec3(0, 0, 0);
int SPostEffectsUtils::m_nFrustrumFrameID = 0;
CTexture* SPostEffectsUtils::m_UpscaleTarget = nullptr;
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::Create()
{
assert(gRenDev);
const SViewport& MainVp = gRenDev->m_MainViewport;
const bool bCreatePostAA = CRenderer::CV_r_AntialiasingMode && !CTexture::IsTextureExist(CTexture::s_ptexPrevBackBuffer[0][0]);
//@NOTE: CV_r_watercaustics will be removed when the infinite ocean component feature toggle is removed.
const bool bCreateCaustics = (CRenderer::CV_r_watervolumecaustics && CRenderer::CV_r_watercaustics) && !CTexture::IsTextureExist(CTexture::s_ptexWaterCaustics[0]);
static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby");
ETEX_Format nHDRReducedFormat = gRenDev->UseHalfFloatRenderTargets() ? eTF_R11G11B10F : eTF_R10G10B10A2;
ETEX_Format taaFormat = eTF_R8G8B8A8;
if (CRenderer::CV_r_AntialiasingMode == eAT_TAA)
{
taaFormat = eTF_R16G16B16A16F;
}
bool taaFormatMismatch = (CRenderer::CV_r_AntialiasingMode && CTexture::s_ptexPrevBackBuffer[0][0] && CTexture::s_ptexPrevBackBuffer[0][0]->GetDstFormat() != taaFormat);
if (!CTexture::s_ptexBackBufferScaled[0] || taaFormatMismatch || m_pScreenRect.right != MainVp.nWidth || m_pScreenRect.bottom != MainVp.nHeight || bCreatePostAA || bCreateCaustics)
{
assert(gRenDev);
const int nWidth = gRenDev->GetWidth();
const int nHeight = gRenDev->GetHeight();
// Update viewport info
m_pScreenRect.left = 0;
m_pScreenRect.top = 0;
m_pScreenRect.right = nWidth;
m_pScreenRect.bottom = nHeight;
if (CRenderer::CV_r_AntialiasingMode)
{
CreateRenderTarget("$PrevBackBuffer0", CTexture::s_ptexPrevBackBuffer[0][0], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, TO_PREVBACKBUFFERMAP0, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
CreateRenderTarget("$PrevBackBuffer1", CTexture::s_ptexPrevBackBuffer[1][0], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, TO_PREVBACKBUFFERMAP1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
if (gRenDev->m_bDualStereoSupport)
{
CreateRenderTarget("$PrevBackBuffer0_R", CTexture::s_ptexPrevBackBuffer[0][1], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, -1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
CreateRenderTarget("$PrevBackBuffer1_R", CTexture::s_ptexPrevBackBuffer[1][1], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, -1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
}
}
else
{
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][1]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][1]);
}
CreateRenderTarget("$Cached3DHud", CTexture::s_ptexCached3DHud, nWidth, nHeight, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$Cached3DHudDownsampled", CTexture::s_ptexCached3DHudScaled, nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
// Scaled versions of the scene target
CreateRenderTarget("$BackBufferScaled_d2", CTexture::s_ptexBackBufferScaled[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D2, FT_DONT_RELEASE);
// Ghosting requires data overframes, need to handle for each GPU in MGPU mode
CreateRenderTarget("$PrevFrameScaled", CTexture::s_ptexPrevFrameScaled, nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaledTemp_d2", CTexture::s_ptexBackBufferScaledTemp[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$WaterVolumeRefl", CTexture::s_ptexWaterVolumeRefl[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, true, nHDRReducedFormat, TO_WATERVOLUMEREFLMAP, FT_DONT_RELEASE);
CreateRenderTarget("$WaterVolumeReflPrev", CTexture::s_ptexWaterVolumeRefl[1], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, true, nHDRReducedFormat, TO_WATERVOLUMEREFLMAPPREV, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaled_d4", CTexture::s_ptexBackBufferScaled[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D4, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaledTemp_d4", CTexture::s_ptexBackBufferScaledTemp[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaled_d8", CTexture::s_ptexBackBufferScaled[2], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D8, FT_DONT_RELEASE);
CreateRenderTarget("$RainDropsAccumRT_0", CTexture::s_ptexRainDropsRT[0], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$RainDropsAccumRT_1", CTexture::s_ptexRainDropsRT[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$RainSSOcclusion0", CTexture::s_ptexRainSSOcclusion[0], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, false, eTF_R8G8B8A8);
CreateRenderTarget("$RainSSOcclusion1", CTexture::s_ptexRainSSOcclusion[1], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, false, eTF_R8G8B8A8);
CreateRenderTarget("$RainOcclusion", CTexture::s_ptexRainOcclusion, RAIN_OCC_MAP_SIZE, RAIN_OCC_MAP_SIZE, Clr_Unknown, false, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
// Water phys simulation requires data overframes, need to handle for each GPU in MGPU mode
CreateRenderTarget("$WaterRipplesDDN_0", CTexture::s_ptexWaterRipplesDDN, 256, 256, Clr_Unknown, 1, true, eTF_R8G8B8A8, TO_WATERRIPPLESMAP);
if (gRenDev->UseHalfFloatRenderTargets())
{
CreateRenderTarget("$WaterVolumeDDN", CTexture::s_ptexWaterVolumeDDN, 64, 64, Clr_Unknown, 1, true, eTF_R16G16B16A16F, TO_WATERVOLUMEMAP);
}
else
{
CreateRenderTarget("$WaterVolumeDDN", CTexture::s_ptexWaterVolumeDDN, 64, 64, Clr_Unknown, 1, true, eTF_R8G8B8A8, TO_WATERVOLUMEMAP);
}
if (CRenderer::CV_r_watervolumecaustics && CRenderer::CV_r_watercaustics) //@NOTE: CV_r_watercaustics will be removed when the infinite ocean component feature toggle is removed.
{
const int nCausticRes = clamp_tpl(CRenderer::CV_r_watervolumecausticsresolution, 256, 4096);
CreateRenderTarget("$WaterVolumeCaustics", CTexture::s_ptexWaterCaustics[0], nCausticRes, nCausticRes, Clr_Unknown, 1, false, eTF_R8G8B8A8, TO_WATERVOLUMECAUSTICSMAP);
CreateRenderTarget("$WaterVolumeCausticsTemp", CTexture::s_ptexWaterCaustics[1], nCausticRes, nCausticRes, Clr_Unknown, 1, false, eTF_R8G8B8A8, TO_WATERVOLUMECAUSTICSMAPTEMP);
}
else
{
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[0]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[1]);
}
#if defined(VOLUMETRIC_FOG_SHADOWS)
int fogShadowBufDiv = (CRenderer::CV_r_FogShadows == 2) ? 4 : 2;
CreateRenderTarget("$VolFogShadowBuf0", CTexture::s_ptexVolFogShadowBuf[0], nWidth / fogShadowBufDiv, nHeight / fogShadowBufDiv, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_VOLFOGSHADOW_BUF);
CreateRenderTarget("$VolFogShadowBuf1", CTexture::s_ptexVolFogShadowBuf[1], nWidth / fogShadowBufDiv, nHeight / fogShadowBufDiv, Clr_Unknown, 1, 0, eTF_R8G8B8A8);
#endif
char str[256];
// TODO: Only create necessary RTs for minimal ring?
for (int i = 0; i < MAX_OCCLUSION_READBACK_TEXTURES; i++)
{
azsprintf(str, "$FlaresOcclusion_%d", i);
CreateRenderTarget(str, CTexture::s_ptexFlaresOcclusionRing[i], CFlareSoftOcclusionQuery::s_nIDColMax, CFlareSoftOcclusionQuery::s_nIDRowMax, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE | FT_STAGE_READBACK);
}
CreateRenderTarget("$FlaresGather", CTexture::s_ptexFlaresGather, CFlareSoftOcclusionQuery::s_nGatherTextureWidth, CFlareSoftOcclusionQuery::s_nGatherTextureHeight, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
}
return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::Release()
{
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][1]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][1]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[0]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[1]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[2]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaledTemp[0]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaledTemp[1]);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeDDN);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeRefl[0]);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeRefl[1]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[0]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[1]);
SAFE_RELEASE(CTexture::s_ptexCached3DHud);
SAFE_RELEASE(CTexture::s_ptexCached3DHudScaled);
SAFE_RELEASE(CTexture::s_ptexPrevFrameScaled);
SAFE_RELEASE(CTexture::s_ptexWaterRipplesDDN);
SAFE_RELEASE(CTexture::s_ptexRainDropsRT[0]);
SAFE_RELEASE(CTexture::s_ptexRainDropsRT[1]);
SAFE_RELEASE(CTexture::s_ptexRainSSOcclusion[0]);
SAFE_RELEASE(CTexture::s_ptexRainSSOcclusion[1]);
SAFE_RELEASE(CTexture::s_ptexRainOcclusion);
#if defined(VOLUMETRIC_FOG_SHADOWS)
SAFE_RELEASE(CTexture::s_ptexVolFogShadowBuf[0]);
SAFE_RELEASE(CTexture::s_ptexVolFogShadowBuf[1]);
#endif
for (int i = 0; i < MAX_OCCLUSION_READBACK_TEXTURES; i++)
{
SAFE_RELEASE(CTexture::s_ptexFlaresOcclusionRing[i]);
}
SAFE_RELEASE(CTexture::s_ptexFlaresGather);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::GetFullScreenTri(SVF_P3F_C4B_T2F pResult[3], int nTexWidth, int nTexHeight, float z, const RECT * pSrcRegion)
{
if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
z = 1.0f - z;
pResult[0].xyz = Vec3(-0.0f, -0.0f, z);
pResult[0].color.dcolor = ~0U;
pResult[0].st = Vec2(0, 0);
pResult[1].xyz = Vec3(-0.0f, 2.0f, z);
pResult[1].color.dcolor = ~0U;
pResult[1].st = Vec2(0, 2);
pResult[2].xyz = Vec3(2.0f, -0.0f, z);
pResult[2].color.dcolor = ~0U;
pResult[2].st = Vec2(2, 0);
if (pSrcRegion)
{
const Vec4 vTexCoordsRegion(2.0f*float(pSrcRegion->left) / nTexWidth,
2.0f*float(pSrcRegion->right) / nTexWidth,
2.0f*float(pSrcRegion->top) / nTexHeight,
2.0f*float(pSrcRegion->bottom) / nTexHeight);
pResult[0].st = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.z);
pResult[1].st = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.w);
pResult[2].st = Vec2(vTexCoordsRegion.y, vTexCoordsRegion.z);
}
}
void SPostEffectsUtils::DrawFullScreenTri(int nTexWidth, int nTexHeight, float z, const RECT * pSrcRegion)
{
SVF_P3F_C4B_T2F screenTri[3];
GetFullScreenTri(screenTri, nTexWidth, nTexHeight, z, pSrcRegion);
CVertexBuffer strip(screenTri, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 3, eptTriangleList);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::DrawScreenQuad([[maybe_unused]] int nTexWidth, [[maybe_unused]] int nTexHeight, float x0, float y0, float x1, float y1)
{
const float z = (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f : 0.0f;
Vec3 vv[4];
vv[0] = Vec3(x0, y0, z);
vv[1] = Vec3(x0, y1, z);
vv[2] = Vec3(x1, y0, z);
vv[3] = Vec3(x1, y1, z);
SVF_P3F_C4B_T2F pScreenQuad[] =
{
{ Vec3(0, 0, 0), {
{0}
}, Vec2(0, 0) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(0, 1) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(1, 0) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(1, 1) },
};
pScreenQuad[0].xyz = vv[0];
pScreenQuad[1].xyz = vv[1];
pScreenQuad[2].xyz = vv[2];
pScreenQuad[3].xyz = vv[3];
gRenDev->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF);
CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::DrawQuad([[maybe_unused]] int nTexWidth, [[maybe_unused]] int nTexHeight,
const Vec2& vxA, const Vec2& vxB, const Vec2& vxC, const Vec2& vxD,
const Vec2& uvA, const Vec2& uvB, const Vec2& uvC, const Vec2& uvD)
{
const float z = (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f : 0.0f;
SVF_P3F_C4B_T2F pScreenQuad[4] =
{
{ Vec3(vxA.x, vxA.y, z), {
{0}
}, uvA },
{ Vec3(vxB.x, vxB.y, z), {
{0}
}, uvB },
{ Vec3(vxD.x, vxD.y, z), {
{0}
}, uvD },
{ Vec3(vxC.x, vxC.y, z), {
{0}
}, uvC }
};
gRenDev->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF);
CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::GetFullScreenTriWPOS(SVF_P3F_T2F_T3F pResult[3], int nTexWidth, int nTexHeight, float z, const RECT *pSrcRegion)
{
UpdateFrustumCorners();
if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
z = 1.0f - z;
pResult[0].p = Vec3(-0.0f, -0.0f, z);
pResult[0].st0 = Vec2(0, 0);
pResult[0].st1 = m_vLT;
pResult[1].p = Vec3(-0.0f, 2.0f, z);
pResult[1].st0 = Vec2(0, 2);
pResult[1].st1 = m_vLB*2.0f - m_vLT;
pResult[2].p = Vec3(2.0f, -0.0f, z);
pResult[2].st0 = Vec2(2, 0);
pResult[2].st1 = m_vRT*2.0f - m_vLT;
if (pSrcRegion)
{
const Vec4 vTexCoordsRegion(2.0f*float(pSrcRegion->left) / nTexWidth,
2.0f*float(pSrcRegion->right) / nTexWidth,
2.0f*float(pSrcRegion->top) / nTexHeight,
2.0f*float(pSrcRegion->bottom) / nTexHeight);
pResult[0].st0 = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.z);
pResult[1].st0 = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.w);
pResult[2].st0 = Vec2(vTexCoordsRegion.y, vTexCoordsRegion.z);
}
}
void SPostEffectsUtils::DrawFullScreenTriWPOS(int nTexWidth, int nTexHeight, float z, const RECT *pSrcRegion)
{
SVF_P3F_T2F_T3F screenTri[3];
GetFullScreenTriWPOS(screenTri, nTexWidth, nTexHeight, z, pSrcRegion);
CVertexBuffer strip(&screenTri[0], eVF_P3F_T2F_T3F);
gRenDev->DrawPrimitivesInternal(&strip, 3, eptTriangleList);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::SetTexture(CTexture* pTex, int nStage, int nFilter, int nClamp, bool bSRGBLookup, DWORD dwBorderColor)
{
if (pTex)
{
STexState TS;
TS.SetFilterMode(nFilter);
TS.SetClampMode(nClamp, nClamp, nClamp);
if (nClamp == TADDR_BORDER)
{
TS.SetBorderColor(dwBorderColor);
}
TS.m_bSRGBLookup = bSRGBLookup;
int nTexState = CTexture::GetTexState(TS);
pTex->Apply(nStage, nTexState);
}
else
{
CTexture::ApplyForID(nStage, 0, -1, -1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::CreateRenderTarget(const char* szTexName, CTexture*& pTex, int nWidth, int nHeight, const ColorF& cClear, [[maybe_unused]] bool bUseAlpha, bool bMipMaps, ETEX_Format eTF, int nCustomID, int nFlags)
{
// check if parameters are valid
if (!nWidth || !nHeight)
{
return 0;
}
uint32 flags = nFlags;
flags |= FT_DONT_STREAM | FT_USAGE_RENDERTARGET | (bMipMaps ? FT_FORCE_MIPS : FT_NOMIPS);
// if texture doesn't exist yet, create it
if (!CTexture::IsTextureExist(pTex))
{
pTex = CTexture::CreateRenderTarget(szTexName, nWidth, nHeight, cClear, eTT_2D, flags, eTF, nCustomID);
}
else
{
pTex->SetFlags(flags);
pTex->SetWidth(nWidth);
pTex->SetHeight(nHeight);
pTex->CreateRenderTarget(eTF, cClear);
}
// Following will mess up don't care resolve/restore actions since Fill() sets textures to be cleared on next draw
#if !defined(CRY_USE_METAL) && !defined(OPENGL_ES)
if (pTex)
{
pTex->Clear();
}
#endif
return CTexture::IsTextureExist(pTex) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::ShBeginPass(CShader* pShader, const CCryNameTSCRC& TechName, uint32 nFlags)
{
assert(pShader);
m_pCurrShader = pShader;
uint32 nPasses;
m_pCurrShader->FXSetTechnique(TechName);
m_pCurrShader->FXBegin(&nPasses, nFlags);
return m_pCurrShader->FXBeginPass(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShEndPass()
{
assert(m_pCurrShader);
m_pCurrShader->FXEndPass();
m_pCurrShader->FXEnd();
m_pCurrShader = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShSetParamVS(const CCryNameR& pParamName, const Vec4& pParam)
{
assert(m_pCurrShader);
m_pCurrShader->FXSetVSFloat(pParamName, &pParam, 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShSetParamPS(const CCryNameR& pParamName, const Vec4& pParam)
{
assert(m_pCurrShader);
m_pCurrShader->FXSetPSFloat(pParamName, &pParam, 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ClearScreen(float r, float g, float b, float a)
{
static CCryNameTSCRC pTechName("ClearScreen");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
Vec4 pClrScrParms = Vec4(r, g, b, a);
static CCryNameR pParamName("clrScrParams");
CShaderMan::s_shPostEffects->FXSetPSFloat(pParamName, &pClrScrParms, 1);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::PrepareGmemDeferredDecals()
{
static CCryNameTSCRC pTechName("PrepareGmemDeferredDecals");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
void SPostEffectsUtils::ClearGmemGBuffer()
{
static CCryNameTSCRC pTechName("ClearGmemGBuffer");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::UpdateFrustumCorners()
{
auto& renderPipeline = gRenDev->m_RP;
auto& threadInfo = renderPipeline.m_TI[renderPipeline.m_nProcessThreadID];
int nFrameID = threadInfo.m_nFrameID;
if (m_nFrustrumFrameID != nFrameID || CRenderer::CV_r_StereoMode == 1)
{
Vec3 frustumCoords[8];
gRenDev->GetViewParameters().CalcVerts(frustumCoords);
m_vRT = frustumCoords[4] - frustumCoords[0];
m_vLT = frustumCoords[5] - frustumCoords[1];
m_vLB = frustumCoords[6] - frustumCoords[2];
m_vRB = frustumCoords[7] - frustumCoords[3];
// Swap order when mirrored culling enabled
if ((gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_MIRRORCULL))
{
m_vLT = frustumCoords[4] - frustumCoords[0];
m_vRT = frustumCoords[5] - frustumCoords[1];
m_vRB = frustumCoords[6] - frustumCoords[2];
m_vLB = frustumCoords[7] - frustumCoords[3];
}
m_nFrustrumFrameID = nFrameID;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::UpdateOverscanBorderAspectRatio()
{
if (gRenDev)
{
const float screenWidth = (float)gRenDev->GetWidth();
const float screenHeight = (float)gRenDev->GetHeight();
Vec2 overscanBorders = Vec2(0.0f, 0.0f);
gRenDev->EF_Query(EFQ_OverscanBorders, overscanBorders);
const float aspectX = (screenWidth * (1.0f - (overscanBorders.y * 2.0f)));
const float aspectY = (screenHeight * (1.0f - (overscanBorders.x * 2.0f)));
m_fOverscanBorderAspectRatio = aspectX / max(aspectY, 0.001f);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
Matrix44& SPostEffectsUtils::GetColorMatrix()
{
CPostEffectsMgr* pPostMgr = PostEffectMgr();
int nFrameID = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_nFrameID;
if (m_nColorMatrixFrameID != nFrameID)
{
// Create color transformation matrices
float fBrightness = pPostMgr->GetByNameF("Global_Brightness");
float fContrast = pPostMgr->GetByNameF("Global_Contrast");
float fSaturation = pPostMgr->GetByNameF("Global_Saturation");
float fColorC = pPostMgr->GetByNameF("Global_ColorC");
float fColorM = pPostMgr->GetByNameF("Global_ColorM");
float fColorY = pPostMgr->GetByNameF("Global_ColorY");
float fColorK = pPostMgr->GetByNameF("Global_ColorK");
float fColorHue = pPostMgr->GetByNameF("Global_ColorHue");
float fUserCyan = pPostMgr->GetByNameF("Global_User_ColorC");
fColorC = fUserCyan;
float fUserMagenta = pPostMgr->GetByNameF("Global_User_ColorM");
fColorM = fUserMagenta;
float fUserYellow = pPostMgr->GetByNameF("Global_User_ColorY");
fColorY = fUserYellow;
float fUserLuminance = pPostMgr->GetByNameF("Global_User_ColorK");
fColorK = fUserLuminance;
float fUserHue = pPostMgr->GetByNameF("Global_User_ColorHue");
fColorHue = fUserHue;
float fUserBrightness = pPostMgr->GetByNameF("Global_User_Brightness");
fBrightness = fUserBrightness;
float fUserContrast = pPostMgr->GetByNameF("Global_User_Contrast");
fContrast = fUserContrast;
float fUserSaturation = pPostMgr->GetByNameF("Global_User_Saturation"); // translate to 0
fSaturation = fUserSaturation;
// Saturation matrix
Matrix44 pSaturationMat;
{
float y = 0.3086f, u = 0.6094f, v = 0.0820f, s = clamp_tpl<float>(fSaturation, -1.0f, 100.0f);
float a = (1.0f - s) * y + s;
float b = (1.0f - s) * y;
float c = (1.0f - s) * y;
float d = (1.0f - s) * u;
float e = (1.0f - s) * u + s;
float f = (1.0f - s) * u;
float g = (1.0f - s) * v;
float h = (1.0f - s) * v;
float i = (1.0f - s) * v + s;
pSaturationMat.SetIdentity();
pSaturationMat.SetRow(0, Vec3(a, d, g));
pSaturationMat.SetRow(1, Vec3(b, e, h));
pSaturationMat.SetRow(2, Vec3(c, f, i));
}
// Create Brightness matrix
Matrix44 pBrightMat;
fBrightness = clamp_tpl<float>(fBrightness, 0.0f, 100.0f);
pBrightMat.SetIdentity();
pBrightMat.SetRow(0, Vec3(fBrightness, 0, 0));
pBrightMat.SetRow(1, Vec3(0, fBrightness, 0));
pBrightMat.SetRow(2, Vec3(0, 0, fBrightness));
// Create Contrast matrix
Matrix44 pContrastMat;
{
float c = clamp_tpl<float>(fContrast, -1.0f, 100.0f);
pContrastMat.SetIdentity();
pContrastMat.SetRow(0, Vec3(c, 0, 0));
pContrastMat.SetRow(1, Vec3(0, c, 0));
pContrastMat.SetRow(2, Vec3(0, 0, c));
pContrastMat.SetColumn(3, 0.5f * Vec3(1.0f - c, 1.0f - c, 1.0f - c));
}
// Create CMKY matrix
Matrix44 pCMKYMat;
{
Vec4 pCMYKParams = Vec4(fColorC + fColorK, fColorM + fColorK, fColorY + fColorK, 1.0f);
pCMKYMat.SetIdentity();
pCMKYMat.SetColumn(3, -Vec3(pCMYKParams.x, pCMYKParams.y, pCMYKParams.z));
}
// Create Hue rotation matrix
Matrix44 pHueMat;
{
pHueMat.SetIdentity();
const Vec3 pHueVec = Vec3(0.57735026f, 0.57735026f, 0.57735026f); // (normalized(1,1,1)
pHueMat = Matrix34::CreateRotationAA(fColorHue * PI, pHueVec);
pHueMat.SetColumn(3, Vec3(0, 0, 0));
}
// Compose final color matrix and set fragment program constants
m_pColorMat = pSaturationMat * (pBrightMat * pContrastMat * pCMKYMat * pHueMat);
m_nColorMatrixFrameID = nFrameID;
}
return m_pColorMat;
}
////////////////////////////////////////////////////////////////////////////////////////////////////