/* * 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 "StdAfx.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); #if AZ_RENDER_TO_TEXTURE_GEM_ENABLED // disregard size changes or texture creation for render scene to texture passes // or we will introduce texture create/delete thrashing if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE) { return false; } #endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED 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"); int DolbyCvarValue = DolbyCvar ? DolbyCvar->GetIVal() : eDVM_Disabled; 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); //CTexture::s_ptexWaterVolumeRefl[0]->DisableMgpuSync(); CreateRenderTarget("$WaterVolumeReflPrev", CTexture::s_ptexWaterVolumeRefl[1], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, true, nHDRReducedFormat, TO_WATERVOLUMEREFLMAPPREV, FT_DONT_RELEASE); //CTexture::s_ptexWaterVolumeRefl[1]->DisableMgpuSync(); 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); //CTexture::s_ptexWaterRipplesDDN->DisableMgpuSync(); 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); } //CTexture::s_ptexWaterVolumeDDN->DisableMgpuSync(); 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(int nTexWidth, 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(int nTexWidth, 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, 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(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(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(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; } ////////////////////////////////////////////////////////////////////////////////////////////////////