Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,234 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "AutoExposure.h"
#include "DriverD3D.h"
void CAutoExposurePass::Init()
{
m_samplerPoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
m_samplerLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
}
void CAutoExposurePass::Shutdown()
{
}
void CAutoExposurePass::Reset()
{
}
void GetSampleOffsets_Downscale4x4Bilinear(uint32 nWidth, uint32 nHeight, Vec4 avSampleOffsets[])
{
float tU = 1.0f / (float)nWidth;
float tV = 1.0f / (float)nHeight;
// Sample from the 16 surrounding points. Since bilinear filtering is being used, specific the coordinate
// exactly halfway between the current texel center (k-1.5) and the neighboring texel center (k-0.5)
int index = 0;
for (int y = 0; y < 4; y += 2)
{
for (int x = 0; x < 4; x += 2, index++)
{
avSampleOffsets[index].x = (x - 1.f) * tU;
avSampleOffsets[index].y = (y - 1.f) * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
}
}
}
void CAutoExposurePass::MeasureLuminance()
{
PROFILE_LABEL_SCOPE("MEASURE_LUMINANCE");
CD3D9Renderer* rd = gcpRendD3D;
uint64 nFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE5]);
int32 curTexture = NUM_HDR_TONEMAP_TEXTURES - 1;
static CCryNameR Param1Name("SampleOffsets");
float tU = 1.0f / (3.0f * CTexture::s_ptexHDRToneMaps[curTexture]->GetWidth());
float tV = 1.0f / (3.0f * CTexture::s_ptexHDRToneMaps[curTexture]->GetHeight());
Vec4 avSampleOffsets[16];
uint32 index = 0;
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
avSampleOffsets[index].x = x * tU;
avSampleOffsets[index].y = y * tV;
avSampleOffsets[index].z = 0;
avSampleOffsets[index].w = 1;
index++;
}
}
uint32 nPasses;
rd->FX_PushRenderTarget(0, CTexture::s_ptexHDRToneMaps[curTexture], NULL);
rd->FX_SetActiveRenderTargets();
rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRToneMaps[curTexture]->GetWidth(), CTexture::s_ptexHDRToneMaps[curTexture]->GetHeight());
CShader* pShader = CShaderMan::s_shHDRPostProcess;
static CCryNameTSCRC TechName("HDRSampleLumInitial");
pShader->FXSetTechnique(TechName);
pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
pShader->FXBeginPass(0);
CTexture::s_ptexHDRTargetScaled[1]->Apply(0, m_samplerLinear);
CTexture::s_ptexSceneNormalsMap->Apply(1, m_samplerLinear);
CTexture::s_ptexSceneDiffuse->Apply(2, m_samplerLinear);
CTexture::s_ptexSceneSpecular->Apply(3, m_samplerLinear);
float s1 = 1.0f / (float) CTexture::s_ptexHDRTargetScaled[1]->GetWidth();
float t1 = 1.0f / (float) CTexture::s_ptexHDRTargetScaled[1]->GetHeight();
// Use rotated grid
Vec4 vSampleLumOffsets0 = Vec4(s1 * 0.95f, t1 * 0.25f, -s1 * 0.25f, t1 * 0.96f);
Vec4 vSampleLumOffsets1 = Vec4(-s1 * 0.96f, -t1 * 0.25f, s1 * 0.25f, -t1 * 0.96f);
static CCryNameR pSampleLumOffsetsName0("SampleLumOffsets0");
static CCryNameR pSampleLumOffsetsName1("SampleLumOffsets1");
pShader->FXSetPSFloat(pSampleLumOffsetsName0, &vSampleLumOffsets0, 1);
pShader->FXSetPSFloat(pSampleLumOffsetsName1, &vSampleLumOffsets1, 1);
bool ret = DrawFullScreenQuad(0.0f, 1.0f - 1.0f * gcpRendD3D->m_CurViewportScale.y, 1.0f * gcpRendD3D->m_CurViewportScale.x, 1.0f);
// important that we always write out valid luminance, even if quad draw fails
if (!ret)
{
rd->FX_ClearTarget(CTexture::s_ptexHDRToneMaps[curTexture], Clr_Dark);
}
pShader->FXEndPass();
rd->FX_PopRenderTarget(0);
curTexture--;
// Initialize the sample offsets for the iterative luminance passes
while (curTexture >= 0)
{
rd->FX_PushRenderTarget(0, CTexture::s_ptexHDRToneMaps[curTexture], NULL);
rd->RT_SetViewport(0, 0, CTexture::s_ptexHDRToneMaps[curTexture]->GetWidth(), CTexture::s_ptexHDRToneMaps[curTexture]->GetHeight());
if (!curTexture)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
}
if (curTexture == 1)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
}
static CCryNameTSCRC TechNameLI("HDRSampleLumIterative");
pShader->FXSetTechnique(TechNameLI);
pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
pShader->FXBeginPass(0);
GetSampleOffsets_Downscale4x4Bilinear(CTexture::s_ptexHDRToneMaps[curTexture + 1]->GetWidth(), CTexture::s_ptexHDRToneMaps[curTexture + 1]->GetHeight(), avSampleOffsets);
pShader->FXSetPSFloat(Param1Name, avSampleOffsets, 4);
CTexture::s_ptexHDRToneMaps[curTexture + 1]->Apply(0, m_samplerLinear);
// Draw a fullscreen quad to sample the RT
ret = DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
// important that we always write out valid luminance, even if quad draw fails
if (!ret)
{
rd->FX_ClearTarget(CTexture::s_ptexHDRToneMaps[curTexture], Clr_Dark);
}
pShader->FXEndPass();
rd->FX_PopRenderTarget(0);
curTexture--;
}
gcpRendD3D->GetDeviceContext().CopyResource(
CTexture::s_ptexHDRMeasuredLuminance[gcpRendD3D->RT_GetCurrGpuID()]->GetDevTexture()->GetBaseTexture(),
CTexture::s_ptexHDRToneMaps[0]->GetDevTexture()->GetBaseTexture());
gRenDev->m_RP.m_FlagsShader_RT = nFlagsShader_RT;
}
void CAutoExposurePass::AdjustExposure()
{
PROFILE_LABEL_SCOPE("EYEADAPTATION");
CD3D9Renderer* rd = gcpRendD3D;
// Swap current & last luminance
const int lumMask = (int32)(sizeof(CTexture::s_ptexHDRAdaptedLuminanceCur) / sizeof(CTexture::s_ptexHDRAdaptedLuminanceCur[0])) - 1;
const int32 numTextures = (int32)max(min(gRenDev->GetActiveGPUCount(), (uint32)(sizeof(CTexture::s_ptexHDRAdaptedLuminanceCur) / sizeof(CTexture::s_ptexHDRAdaptedLuminanceCur[0]))), 1u);
CTexture::s_nCurLumTextureIndex++;
CTexture* pTexPrev = CTexture::s_ptexHDRAdaptedLuminanceCur[(CTexture::s_nCurLumTextureIndex - numTextures) & lumMask];
CTexture* pTexCur = CTexture::s_ptexHDRAdaptedLuminanceCur[CTexture::s_nCurLumTextureIndex & lumMask];
CTexture::s_ptexCurLumTexture = pTexCur;
assert(pTexCur);
CShader* pShader = CShaderMan::s_shHDRPostProcess;
uint32 nPasses;
static CCryNameTSCRC TechName("HDRCalculateAdaptedLum");
pShader->FXSetTechnique(TechName);
pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
rd->FX_PushRenderTarget(0, pTexCur, NULL);
rd->RT_SetViewport(0, 0, pTexCur->GetWidth(), pTexCur->GetHeight());
pShader->FXBeginPass(0);
{
Vec4 elapsedTime;
elapsedTime[0] = iTimer->GetFrameTime() * numTextures;
elapsedTime[1] = 1.0f - expf(-CRenderer::CV_r_HDREyeAdaptationSpeed * elapsedTime[0]);
elapsedTime[2] = 0;
elapsedTime[3] = 0;
if (rd->GetCamera().IsJustActivated() || rd->m_nDisableTemporalEffects > 0)
{
elapsedTime[1] = 1.0f;
elapsedTime[2] = 1.0f;
}
static CCryNameR Param1Name("ElapsedTime");
pShader->FXSetPSFloat(Param1Name, &elapsedTime, 1);
}
pTexPrev->Apply(0, m_samplerPoint);
CTexture::s_ptexHDRToneMaps[0]->Apply(1, m_samplerPoint);
// Draw a fullscreen quad to sample the RT
DrawFullScreenQuad(0.0f, 0.0f, 1.0f, 1.0f);
pShader->FXEndPass();
rd->FX_PopRenderTarget(0);
}
void CAutoExposurePass::Execute()
{
MeasureLuminance();
AdjustExposure();
}
@@ -0,0 +1,37 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
class CAutoExposurePass
: public GraphicsPipelinePass
{
public:
virtual ~CAutoExposurePass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
void MeasureLuminance();
void AdjustExposure();
private:
int m_samplerPoint;
int m_samplerLinear;
};
@@ -0,0 +1,109 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "Bloom.h"
#include "DriverD3D.h"
void CBloomPass::Init()
{
}
void CBloomPass::Shutdown()
{
Reset();
}
void CBloomPass::Reset()
{
m_pass1H.Reset();
m_pass1V.Reset();
m_pass2H.Reset();
m_pass2V.Reset();
}
void CBloomPass::Execute()
{
// Approximate function (1 - r)^4 by a sum of Gaussians: 0.0174*G(0.008,r) + 0.192*G(0.0576,r)
const float sigma1 = sqrtf(0.008f);
const float sigma2 = sqrtf(0.0576f - 0.008f);
PROFILE_LABEL_SCOPE("BLOOM_GEN");
CD3D9Renderer* rd = gcpRendD3D;
static CCryNameTSCRC techName("HDRBloomGaussian");
static CCryNameR szHDRParam0("HDRParams0");
int width = CTexture::s_ptexHDRFinalBloom->GetWidth();
int height = CTexture::s_ptexHDRFinalBloom->GetHeight();
// Note: Just scaling the sampling offsets depending on the resolution is not very accurate but works acceptably
assert(CTexture::s_ptexHDRFinalBloom->GetWidth() == CTexture::s_ptexHDRTarget->GetWidth() / 4);
float scaleW = ((float)width / 400.0f) / (float)width;
float scaleH = ((float)height / 225.0f) / (float)height;
int texStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
int texFilter = (CTexture::s_ptexHDRFinalBloom->GetWidth() == 400 && CTexture::s_ptexHDRFinalBloom->GetHeight() == 225) ? texStatePoint : texStateLinear;
rd->RT_SetViewport(0, 0, width, height);
// Pass 1 Horizontal
m_pass1H.SetRenderTarget(0, CTexture::s_ptexHDRTempBloom[1]);
m_pass1H.SetTechnique(CShaderMan::s_shHDRPostProcess, techName, 0);
m_pass1H.SetState(GS_NODEPTHTEST);
m_pass1H.SetTextureSamplerPair(0, CTexture::s_ptexHDRTargetScaled[1], texFilter);
m_pass1H.SetTextureSamplerPair(2, CTexture::s_ptexHDRToneMaps[0], texStatePoint);
m_pass1H.BeginConstantUpdate();
Vec4 v = Vec4(scaleW, 0, 0, 0);
CShaderMan::s_shHDRPostProcess->FXSetPSFloat(szHDRParam0, &v, 1);
m_pass1H.Execute();
// Pass 1 Vertical
m_pass1V.SetRenderTarget(0, CTexture::s_ptexHDRTempBloom[0]);
m_pass1V.SetTechnique(CShaderMan::s_shHDRPostProcess, techName, 0);
m_pass1V.SetState(GS_NODEPTHTEST);
m_pass1V.SetTextureSamplerPair(0, CTexture::s_ptexHDRTempBloom[1], texFilter);
m_pass1V.SetTextureSamplerPair(2, CTexture::s_ptexHDRToneMaps[0], texStatePoint);
m_pass1V.BeginConstantUpdate();
v = Vec4(0, scaleH, 0, 0);
CShaderMan::s_shHDRPostProcess->FXSetPSFloat(szHDRParam0, &v, 1);
m_pass1V.Execute();
// Pass 2 Horizontal
m_pass2H.SetRenderTarget(0, CTexture::s_ptexHDRTempBloom[1]);
m_pass2H.SetTechnique(CShaderMan::s_shHDRPostProcess, techName, 0);
m_pass2H.SetState(GS_NODEPTHTEST);
m_pass2H.SetTextureSamplerPair(0, CTexture::s_ptexHDRTempBloom[0], texFilter);
m_pass2H.SetTextureSamplerPair(2, CTexture::s_ptexHDRToneMaps[0], texStatePoint);
m_pass2H.BeginConstantUpdate();
v = Vec4((sigma2 / sigma1) * scaleW, 0, 0, 0);
CShaderMan::s_shHDRPostProcess->FXSetPSFloat(szHDRParam0, &v, 1);
m_pass2H.Execute();
// Pass 2 Vertical
m_pass2V.SetRenderTarget(0, CTexture::s_ptexHDRFinalBloom);
m_pass2V.SetTechnique(CShaderMan::s_shHDRPostProcess, techName, g_HWSR_MaskBit[HWSR_SAMPLE0]);
m_pass2V.SetState(GS_NODEPTHTEST);
m_pass2V.SetTextureSamplerPair(0, CTexture::s_ptexHDRTempBloom[1], texFilter);
m_pass2V.SetTextureSamplerPair(1, CTexture::s_ptexHDRTempBloom[0], texFilter);
m_pass2V.SetTextureSamplerPair(2, CTexture::s_ptexHDRToneMaps[0], texStatePoint);
m_pass2V.BeginConstantUpdate();
v = Vec4(0, (sigma2 / sigma1) * scaleH, 0, 0);
CShaderMan::s_shHDRPostProcess->FXSetPSFloat(szHDRParam0, &v, 1);
m_pass2V.Execute();
}
@@ -0,0 +1,35 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
class CBloomPass
: public GraphicsPipelinePass
{
public:
virtual ~CBloomPass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
CFullscreenPass m_pass1H;
CFullscreenPass m_pass1V;
CFullscreenPass m_pass2H;
CFullscreenPass m_pass2V;
};
@@ -0,0 +1,208 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "FullscreenPass.h"
#include "CryCustomTypes.h"
#include "DriverD3D.h"
#include "../Common/PostProcess/PostProcessUtils.h"
uint64 CFullscreenPass::s_prevRTMask = 0;
CFullscreenPass::CFullscreenPass()
{
m_pShader = NULL;
m_renderState = 0;
m_rtMask = 0;
m_dirtyMask = ~0;
m_bRequireWPos = false;
m_pRenderTargets.fill(NULL);
m_vertexBuffer = ~0u;
auto& factory = CDeviceObjectFactory::GetInstance();
m_pResources = factory.CreateResourceSet(CDeviceResourceSet::EFlags_ForceSetAllState);
m_pResourceLayout = factory.CreateResourceLayout();
}
CFullscreenPass::~CFullscreenPass()
{
Reset();
}
void CFullscreenPass::Reset()
{
m_ReflectedConstantBuffers.clear();
m_dirtyMask = ~0;
}
void CFullscreenPass::BeginConstantUpdate()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
s_prevRTMask = rd->m_RP.m_FlagsShader_RT;
rd->m_RP.m_FlagsShader_RT = m_rtMask;
if (m_dirtyMask || m_pResources->IsDirty())
{
m_dirtyMask = CompileResources();
}
uint32 numPasses;
m_pShader->FXSetTechnique(m_techniqueName);
m_pShader->FXBegin(&numPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
SDeviceObjectHelpers::BeginUpdateConstantBuffers(m_ReflectedConstantBuffers);
}
void CFullscreenPass::Execute()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
// dummy PushRenderTarget here so we can directly set the target via the command list
rd->FX_PushRenderTarget(0, m_pRenderTargets[0], NULL);
// unmap constant buffers and mark as bound
SDeviceObjectHelpers::EndUpdateConstantBuffers(m_ReflectedConstantBuffers);
if (m_dirtyMask == 0)
{
// update vertex buffer if required
if (m_bRequireWPos)
{
UpdateVertexBuffer();
}
size_t bufferOffset;
uint32 stride = m_bRequireWPos ? sizeof(SVF_P3F_T2F_T3F) : sizeof(SVF_P3F_C4B_T2F);
D3DBuffer* pVB = rd->m_DevBufMan.GetD3D(m_vertexBuffer, &bufferOffset);
// fullscreen viewport
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(FullscreenPass_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
D3DViewPort viewPort = { 0.0f, 0.0f, static_cast<float>(m_pRenderTargets[0]->GetWidth()), static_cast<float>(m_pRenderTargets[0]->GetHeight()), 0.f, 1.f };
#endif
D3D11_RECT viewPortRect = { (LONG)viewPort.TopLeftX, (LONG)viewPort.TopLeftY, LONG(viewPort.TopLeftX + viewPort.Width), LONG(viewPort.TopLeftY + viewPort.Height) };
uint32 bindSlot = 0;
CDeviceGraphicsCommandListPtr pCommandList = CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList();
pCommandList->SetRenderTargets(m_pRenderTargets.size(), &m_pRenderTargets[0], NULL);
pCommandList->SetViewports(1, &viewPort);
pCommandList->SetScissorRects(1, &viewPortRect);
pCommandList->SetPipelineState(m_pPipelineState);
pCommandList->SetResourceLayout(m_pResourceLayout.get());
for (int i = 0; i < m_ReflectedConstantBuffers.size(); ++i)
{
pCommandList->SetInlineConstantBuffer(bindSlot++, m_ReflectedConstantBuffers[i].pBuffer, m_ReflectedConstantBuffers[i].shaderSlot, m_ReflectedConstantBuffers[i].shaderClass);
}
pCommandList->SetInlineConstantBuffer(bindSlot++, rd->GetGraphicsPipeline().GetPerViewConstantBuffer(), eConstantBufferShaderSlot_PerView, EShaderStage_Vertex | EShaderStage_Pixel);
pCommandList->SetInlineConstantBuffer(bindSlot++, rd->GetGraphicsPipeline().GetPerFrameConstantBuffer(), eConstantBufferShaderSlot_PerFrame, EShaderStage_Vertex | EShaderStage_Pixel);
pCommandList->SetResources(bindSlot++, m_pResources.get());
pCommandList->SetVertexBuffers(1, &pVB, &bufferOffset, &stride);
pCommandList->Draw(3, 1, 0, 0);
}
m_pShader->FXEndPass();
m_pShader->FXEnd();
rd->FX_PopRenderTarget(0);
rd->m_RP.m_FlagsShader_RT = s_prevRTMask;
}
uint CFullscreenPass::CompileResources()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
// get required constant buffers
bool shadersAvailable = SDeviceObjectHelpers::GetConstantBuffersFromShader(m_ReflectedConstantBuffers, m_pShader, m_techniqueName, m_rtMask, 0, 0);
if (!shadersAvailable)
return 0xFFFFFFFF;
// textures
m_pResources->Build();
int bindSlot = 0;
// resource mapping
m_pResourceLayout->Clear();
for (int i = 0; i < m_ReflectedConstantBuffers.size(); ++i)
{
m_pResourceLayout->SetConstantBuffer(bindSlot++, m_ReflectedConstantBuffers[i].shaderSlot, SHADERSTAGE_FROM_SHADERCLASS(m_ReflectedConstantBuffers[i].shaderClass));
}
m_pResourceLayout->SetConstantBuffer(bindSlot++, eConstantBufferShaderSlot_PerView, EShaderStage_Vertex | EShaderStage_Pixel);
m_pResourceLayout->SetConstantBuffer(bindSlot++, eConstantBufferShaderSlot_PerFrame, EShaderStage_Vertex | EShaderStage_Pixel);
m_pResourceLayout->SetResourceSet(bindSlot++, m_pResources);
if (!m_pResourceLayout->Build())
{
return 0xFFFFFFFF;
}
// pipeline state
CDeviceGraphicsPSODesc psoDesc(m_pResourceLayout.get(), m_pShader, m_techniqueName, m_rtMask, 0, 0, false);
psoDesc.m_RenderState = m_renderState;
psoDesc.m_VertexFormat = m_bRequireWPos ? eVF_P3F_T2F_T3F : eVF_P3F_C4B_T2F;
psoDesc.m_PrimitiveType = eptTriangleStrip;
for (int i = 0; i < m_pRenderTargets.size(); ++i)
{
psoDesc.m_RenderTargetFormats[i] = m_pRenderTargets[i] ? m_pRenderTargets[i]->GetDstFormat() : eTF_Unknown;
}
psoDesc.Build();
m_pPipelineState = CDeviceObjectFactory::GetInstance().CreateGraphicsPSO(psoDesc);
if (!m_pPipelineState)
{
return 0xFFFFFFFF;
}
// vertex buffer
if (m_vertexBuffer != ~0u)
{
rd->m_DevBufMan.Destroy(m_vertexBuffer);
}
m_vertexBuffer = rd->m_DevBufMan.Create(BBT_VERTEX_BUFFER, m_bRequireWPos ? BU_DYNAMIC : BU_STATIC, 3 * (m_bRequireWPos ? sizeof(SVF_P3F_T2F_T3F) : sizeof(SVF_P3F_C4B_T2F)));
UpdateVertexBuffer();
return 0;
}
void CFullscreenPass::UpdateVertexBuffer()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
void* data = rd->m_DevBufMan.BeginWrite(m_vertexBuffer);
if (m_bRequireWPos)
{
SVF_P3F_T2F_T3F result[3];
SPostEffectsUtils::GetFullScreenTriWPOS(result, 0, 0);
memcpy(data, result, sizeof(result));
}
else
{
SVF_P3F_C4B_T2F result[3];
SPostEffectsUtils::GetFullScreenTri(result, 0, 0);
memcpy(data, result, sizeof(result));
}
rd->m_DevBufMan.EndReadWrite(m_vertexBuffer);
}
@@ -0,0 +1,93 @@
/*
* 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.
#pragma once
#include <array>
class CFullscreenPass
{
public:
CFullscreenPass();
~CFullscreenPass();
#define ASSIGN_VALUE(dst, src, dirtyFlag) \
if ((dst) != (src)) { \
m_dirtyMask |= (dirtyFlag); } \
(dst) = (src);
void SetRenderTarget(uint32 slot, CTexture* pRenderTarget)
{
ASSIGN_VALUE(m_pRenderTargets[slot], pRenderTarget, 0xFFFFFFFF);
}
void SetTechnique(CShader* pShader, CCryNameTSCRC& techName, uint64 rtMask)
{
ASSIGN_VALUE(m_pShader, pShader, 0xFFFFFFFF);
ASSIGN_VALUE(m_techniqueName, techName, 0xFFFFFFFF);
ASSIGN_VALUE(m_rtMask, rtMask, 0xFFFFFFFF);
}
void SetTexture(uint32 slot, CTexture* pTexture, SResourceView::KeyType resourceViewID = SResourceView::DefaultView)
{
m_pResources->SetTexture(slot, pTexture, resourceViewID);
}
void SetSampler(uint32 slot, int32 sampler)
{
m_pResources->SetSampler(slot, sampler);
}
void SetTextureSamplerPair(uint32 slot, CTexture* pTex, int32 sampler, SResourceView::KeyType resourceViewID = SResourceView::DefaultView)
{
m_pResources->SetTexture(slot, pTex, resourceViewID);
m_pResources->SetSampler(slot, sampler);
}
void SetState(int state)
{
ASSIGN_VALUE(m_renderState, state, 0xFFFFFFFF);
}
void SetRequireWorldPos(bool bRequireWPos)
{
ASSIGN_VALUE(m_bRequireWPos, bRequireWPos, 0xFFFFFFFF);
}
#undef ASSIGN_VALUE
void BeginConstantUpdate();
void Execute();
void Reset();
private:
typedef SDeviceObjectHelpers::SConstantBufferBindInfo CBufferBindInfo;
uint CompileResources();
void UpdateVertexBuffer();
std::array<CTexture*, 1> m_pRenderTargets;
CDeviceResourceSetPtr m_pResources;
std::vector<CBufferBindInfo> m_ReflectedConstantBuffers;
CDeviceResourceLayoutPtr m_pResourceLayout;
CDeviceGraphicsPSOPtr m_pPipelineState;
CShader* m_pShader;
CCryNameTSCRC m_techniqueName;
uint64 m_rtMask;
int m_renderState;
uint m_dirtyMask;
bool m_bRequireWPos;
buffer_handle_t m_vertexBuffer;
static uint64 s_prevRTMask;
};
@@ -0,0 +1,81 @@
/*
* 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.
#pragma once
template <typename T, int constantBufferSlot>
class CTypedConstantBuffer
{
T m_hostBuffer;
CConstantBuffer* m_constantBuffer;
public:
CTypedConstantBuffer()
: m_constantBuffer(nullptr) {}
CConstantBuffer* GetDeviceConstantBuffer()
{
if (!m_constantBuffer)
{
CreateDeviceBuffer();
}
return m_constantBuffer;
}
void CreateDeviceBuffer()
{
int size = sizeof(T);
m_constantBuffer = gcpRendD3D->m_DevBufMan.CreateConstantBuffer(size);
}
void CopyToDevice()
{
D3D11_MAPPED_SUBRESOURCE mapped;
HRESULT hr =
gcpRendD3D.GetDeviceContext().Map(m_constantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped);
if (hr != S_OK)
{
return;
}
memcpy(mapped.pData, &m_hostBuffer, sizeof(T));
gcpRendD3D.GetDeviceContext().Unmap(m_constantBuffer, 0);
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(GraphicsHelpers_h)
#endif
}
void Bind()
{
ID3D11Buffer* buf[] = { m_constantBuffer };
gcpRendD3D.GetDeviceContext().CSSetConstantBuffers(constantBufferSlot, 1u, buf);
}
void BindPixelShader()
{
ID3D11Buffer* buf[] = { m_constantBuffer };
gcpRendD3D.GetDeviceContext().PSSetConstantBuffers(constantBufferSlot, 1u, buf);
}
void BindGeometryShader()
{
ID3D11Buffer* buf[] = { m_constantBuffer };
gcpRendD3D.GetDeviceContext().GSSetConstantBuffers(constantBufferSlot, 1u, buf);
}
T* operator->() { return &m_hostBuffer; }
bool IsDeviceBufferAllocated() { return m_constantBuffer != nullptr; }
T& operator=(const T& hostData)
{
return m_hostBuffer = hostData;
}
};
@@ -0,0 +1,19 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "GraphicsPipeline.h"
CGraphicsPipeline::~CGraphicsPipeline()
{
}
@@ -0,0 +1,48 @@
/*
* 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.
#pragma once
#include "GraphicsPipelinePass.h"
class CGraphicsPipeline
{
public:
virtual ~CGraphicsPipeline();
// Allocate resources needed by the pipeline & passes
virtual void Init() = 0;
// Free resources needed by the pipeline & passes
virtual void Shutdown() = 0;
// Prepare all passes before actual drawing starts
virtual void Prepare() = 0;
// Execute the pipeline and its passes
virtual void Execute() = 0;
// Reset all render passes and their PSOs
// Needed if shaders need to be reloaded
virtual void Reset() = 0;
protected:
template<class T>
void RegisterPass(T*& pPass)
{
pPass = new T();
pPass->Init();
m_passes.emplace_back(pPass);
}
protected:
std::vector<std::unique_ptr<GraphicsPipelinePass>> m_passes;
};
@@ -0,0 +1,75 @@
/*
* 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.
#pragma once
#include <Range.h>
#include "GraphicsPipelineStateSet.h"
// forward declarations
typedef std::shared_ptr<CGraphicsPipelineStateLocalCache> CGraphicsPipelineStateLocalCachePtr;
class GraphicsPipelinePass;
struct SGraphicsPiplinePassContext
{
SGraphicsPiplinePassContext(GraphicsPipelinePass* pass, EShaderTechniqueID technique, uint32 filter)
: pPass(pass)
, techniqueID(technique)
, batchFilter(filter)
, nFrameID(0)
, renderListId(EFSLIST_INVALID)
, sortGroupID(0)
, passId(0)
, passSubId(0)
, pPipelineStats(0)
{
}
GraphicsPipelinePass* pPass;
EShaderTechniqueID techniqueID;
uint32 batchFilter;
ERenderListID renderListId;
int sortGroupID;
threadID nProcessThreadID;
uint64 nFrameID;
// One of ERenderableTechnique
uint32 passId;
// When pass have multiple sub-passes, specified here, selects a different PSO from compiled render object.
uint32 passSubId;
// Current pipeline stats.
SPipeStat* pPipelineStats;
// rend items
TRange<int> rendItems;
};
class GraphicsPipelinePass
{
public:
virtual ~GraphicsPipelinePass() {}
// Allocate resources needed by the pipeline pass
virtual void Init() = 0;
// Free resources used by the pipeline pass
virtual void Shutdown() = 0;
// Prepare pass before actual rendering starts (called every frame)
virtual void Prepare() {};
// Force pass to reset data
virtual void Reset() = 0;
// initialize command list with pass specific data
virtual void PrepareCommandList([[maybe_unused]] CDeviceGraphicsCommandListRef RESTRICT_REFERENCE commandList) const {}
};
@@ -0,0 +1,101 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "GraphicsPipelineStateSet.h"
#include "GraphicsPipelinePass.h"
#include "DriverD3D.h"
#include <AzCore/std/hash.h>
SGraphicsPipelineStateDescription::SGraphicsPipelineStateDescription(
CRenderObject* pObj,
const SShaderItem& _shaderItem,
EShaderTechniqueID _technique,
AZ::Vertex::Format _vertexFormat,
uint32 _streamMask,
int _primitiveType)
{
shaderItem = _shaderItem;
technique = _technique;
objectFlags = pObj->m_ObjFlags;
objectFlags_MDV = pObj->m_nMDV;
objectRuntimeMask = pObj->m_nRTMask;
vertexFormat = _vertexFormat;
streamMask = _streamMask;
primitiveType = _primitiveType;
AZ_PUSH_DISABLE_WARNING(, "-Wconstant-logical-operand")
if ((pObj->m_ObjFlags & FOB_SKINNED) && CRenderer::CV_r_usehwskinning && !CRenderer::CV_r_character_nodeform)
AZ_POP_DISABLE_WARNING
{
SSkinningData* pSkinningData = NULL;
SRenderObjData* pOD = pObj->GetObjData();
if (pOD && (pSkinningData = pOD->m_pSkinningData))
{
if (pSkinningData->nHWSkinningFlags & eHWS_Skinning_Matrix)
{
objectRuntimeMask |= (g_HWSR_MaskBit[HWSR_SKINNING_MATRIX]);
}
else if (pSkinningData->nHWSkinningFlags & eHWS_Skinning_DQ_Linear)
{
objectRuntimeMask |= (g_HWSR_MaskBit[HWSR_SKINNING_DQ_LINEAR]);
}
else
{
objectRuntimeMask |= (g_HWSR_MaskBit[HWSR_SKINNING_DUAL_QUAT]);
}
}
}
}
CDeviceGraphicsPSOPtr CGraphicsPipelineStateLocalCache::FindState(uint64 stateHashKey) const
{
for (auto const& state : m_states)
{
if (state.stateHashKey == stateHashKey)
{
return state.m_pipelineState;
}
}
return nullptr;
}
uint64 CGraphicsPipelineStateLocalCache::GetHashKey(const SGraphicsPipelineStateDescription& desc) const
{
AZStd::hash<const SGraphicsPipelineStateDescription*> hasher;
uint64 key = hasher(&desc);
return key;
}
const DevicePipelineStatesArray* CGraphicsPipelineStateLocalCache::Find(const SGraphicsPipelineStateDescription& desc) const
{
uint64 key = GetHashKey(desc);
for (auto const& state : m_states)
{
if (state.stateHashKey == key && state.description == desc)
{
return &state.m_pipelineStates;
}
}
return nullptr;
}
void CGraphicsPipelineStateLocalCache::Put(const SGraphicsPipelineStateDescription& desc, const DevicePipelineStatesArray& states)
{
// Cache this state locally.
CachedState cache;
cache.stateHashKey = GetHashKey(desc);
cache.description = desc;
cache.m_pipelineStates = states;
m_states.push_back(cache);
}
@@ -0,0 +1,72 @@
/*
* 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.
#pragma once
#include "DeviceManager/DeviceWrapper12.h"
class GraphicsPipelinePass;
struct SGraphicsPipelineStateDescription
{
SShaderItem shaderItem;
EShaderTechniqueID technique;
uint64 objectFlags;
uint64 objectRuntimeMask;
uint32 objectFlags_MDV;
AZ::Vertex::Format vertexFormat;
uint32 streamMask;
int primitiveType;
SGraphicsPipelineStateDescription()
: technique(TTYPE_Z)
, objectFlags(0)
, objectFlags_MDV(0)
, objectRuntimeMask(0)
, vertexFormat(eVF_Unknown)
, streamMask(0)
, primitiveType(0)
{};
SGraphicsPipelineStateDescription(CRenderObject* pObj, const SShaderItem& shaderItem, EShaderTechniqueID technique, AZ::Vertex::Format vertexFormat, uint32 streamMask, int primitiveType);
bool operator==(const SGraphicsPipelineStateDescription& other) const
{
return 0 == memcmp(this, &other, sizeof(*this));
}
};
// Array of pass id and PipelineState
typedef std::array<CDeviceGraphicsPSOPtr, 4> DevicePipelineStatesArray;
// Set of precomputed Pipeline States
class CGraphicsPipelineStateLocalCache
{
public:
const DevicePipelineStatesArray* Find(const SGraphicsPipelineStateDescription& desc) const;
void Put(const SGraphicsPipelineStateDescription& desc, const DevicePipelineStatesArray& states);
private:
CDeviceGraphicsPSOPtr FindState(uint64 stateHashKey) const;
void StoreState(uint64 stateHashKey, CDeviceGraphicsPSOPtr pso) const;
uint64 GetHashKey(const SGraphicsPipelineStateDescription& desc) const;
private:
struct CachedState
{
uint64 stateHashKey;
SGraphicsPipelineStateDescription description;
CDeviceGraphicsPSOPtr m_pipelineState;
DevicePipelineStatesArray m_pipelineStates;
};
std::vector<CachedState> m_states;
};
typedef std::shared_ptr<CGraphicsPipelineStateLocalCache> CGraphicsPipelineStateLocalCachePtr;
@@ -0,0 +1,215 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "UtilityPasses.h"
#include "FullscreenPass.h"
#include "DriverD3D.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CStretchRectPass
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void CStretchRectPass::Execute(CTexture* pSrcTex, CTexture* pDestTex)
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (pSrcTex == NULL || pDestTex == NULL)
{
return;
}
PROFILE_LABEL_SCOPE("STRETCHRECT");
bool bResample = pSrcTex->GetWidth() != pDestTex->GetWidth() || pSrcTex->GetHeight() != pDestTex->GetHeight();
const D3DFormat destFormat = CTexture::DeviceFormatFromTexFormat(pDestTex->GetDstFormat());
const D3DFormat srcFormat = CTexture::DeviceFormatFromTexFormat(pSrcTex->GetDstFormat());
if (!bResample && destFormat == srcFormat)
{
rd->GetDeviceContext().CopyResource(pDestTex->GetDevTexture()->GetBaseTexture(), pSrcTex->GetDevTexture()->GetBaseTexture());
return;
}
static CCryNameTSCRC techTexToTex("TextureToTexture");
static CCryNameTSCRC techTexToTexResampled("TextureToTextureResampled");
m_pass.SetRenderTarget(0, pDestTex);
m_pass.SetTechnique(CShaderMan::s_shPostEffects, bResample ? techTexToTexResampled : techTexToTex, 0);
m_pass.SetState(GS_NODEPTHTEST);
int texFilter = CTexture::GetTexState(STexState(bResample ? FILTER_LINEAR : FILTER_POINT, true));
m_pass.SetTextureSamplerPair(0, pSrcTex, texFilter);
static CCryNameR param0Name("texToTexParams0");
static CCryNameR param1Name("texToTexParams1");
const bool bBigDownsample = false; // TODO
CTexture* pOffsetTex = bBigDownsample ? pDestTex : pSrcTex;
float s1 = 0.5f / (float) pOffsetTex->GetWidth(); // 2.0 better results on lower res images resizing
float t1 = 0.5f / (float) pOffsetTex->GetHeight();
Vec4 params0, params1;
if (bBigDownsample)
{
// Use rotated grid + middle sample (~Quincunx)
params0 = Vec4(s1 * 0.96f, t1 * 0.25f, -s1 * 0.25f, t1 * 0.96f);
params1 = Vec4(-s1 * 0.96f, -t1 * 0.25f, s1 * 0.25f, -t1 * 0.96f);
}
else
{
// Use box filtering (faster - can skip bilinear filtering, only 4 taps)
params0 = Vec4(-s1, -t1, s1, -t1);
params1 = Vec4(s1, t1, -s1, t1);
}
m_pass.BeginConstantUpdate();
CShaderMan::s_shPostEffects->FXSetPSFloat(param0Name, &params0, 1);
CShaderMan::s_shPostEffects->FXSetPSFloat(param1Name, &params1, 1);
m_pass.Execute();
}
void CStretchRectPass::Reset()
{
m_pass.Reset();
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CGaussianBlurPass
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline float CGaussianBlurPass::GaussianDistribution1D(float x, float rho)
{
float g = 1.0f / (rho * sqrtf(2.0f * PI));
g *= expf(-(x * x) / (2.0f * rho * rho));
return g;
}
void CGaussianBlurPass::ComputeParams(int texWidth, int texHeight, int numSamples, float scale, float distribution)
{
assert(numSamples <= 16);
const int halfNumSamples = (numSamples >> 1);
float s1 = 1.0f / (float)texWidth;
float t1 = 1.0f / (float)texHeight;
float weights[16];
float weightSum = 0.0f;
// Compute Gaussian weights
for (int s = 0; s < numSamples; ++s)
{
if (distribution != 0.0f)
{
weights[s] = GaussianDistribution1D((float)(s - halfNumSamples), distribution);
}
else
{
weights[s] = 0.0f;
}
weightSum += weights[s];
}
// Normalize weights
for (int s = 0; s < numSamples; ++s)
{
weights[s] /= weightSum;
}
// Compute bilinear offsets
for (int s = 0; s < halfNumSamples; ++s)
{
float off_a = weights[s * 2];
float off_b = ((s * 2 + 1) <= numSamples - 1) ? weights[s * 2 + 1] : 0;
float a_plus_b = (off_a + off_b);
if (a_plus_b == 0)
{
a_plus_b = 1.0f;
}
float offset = off_b / a_plus_b;
weights[s] = off_a + off_b;
weights[s] *= scale;
m_weights[s] = Vec4(1, 1, 1, 1) * weights[s];
float currOffset = (float)s * 2.0f + offset - (float)halfNumSamples;
m_paramsH[s] = Vec4(s1 * currOffset, 0, 0, 0);
m_paramsV[s] = Vec4(0, t1 * currOffset, 0, 0);
}
}
void CGaussianBlurPass::Execute(CTexture* pTex, CTexture* pTempTex, float scale, float distribution)
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (pTex == NULL || pTempTex == NULL)
{
return;
}
PROFILE_LABEL_SCOPE("TEXBLUR_GAUSSIAN");
CShader* pShader = CShaderMan::s_shPostEffects;
int texFilter = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
static CCryNameTSCRC techDefault("GaussBlurBilinear");
static CCryNameR clampTCName("clampTC");
static CCryNameR param0Name("psWeights");
static CCryNameR param1Name("PI_psOffsets");
Vec4 clampTC(0.0f, 1.0f, 0.0f, 1.0f);
if (pTex->GetWidth() == rd->GetWidth() && pTex->GetHeight() == rd->GetHeight())
{
// Clamp manually in shader since texture clamp won't apply for smaller viewport
clampTC = Vec4(0.0f, rd->m_RP.m_CurDownscaleFactor.x, 0.0f, rd->m_RP.m_CurDownscaleFactor.y);
}
const int numSamples = 16;
if (m_scale != scale || m_distribution != distribution)
{
ComputeParams(pTex->GetWidth(), pTex->GetHeight(), numSamples, scale, distribution);
m_scale = scale;
m_distribution = distribution;
}
// Horizontal
m_passH.SetRenderTarget(0, pTempTex);
m_passH.SetTechnique(pShader, techDefault, 0);
m_passH.SetState(GS_NODEPTHTEST);
m_passH.SetTextureSamplerPair(0, pTex, texFilter);
m_passH.BeginConstantUpdate();
pShader->FXSetVSFloat(param1Name, m_paramsH, numSamples / 2);
pShader->FXSetPSFloat(param0Name, m_weights, numSamples / 2);
pShader->FXSetPSFloat(clampTCName, &clampTC, 1);
m_passH.Execute();
// Vertical
m_passV.SetRenderTarget(0, pTex);
m_passV.SetTechnique(pShader, techDefault, 0);
m_passV.SetState(GS_NODEPTHTEST);
m_passV.SetTextureSamplerPair(0, pTempTex, texFilter);
m_passV.BeginConstantUpdate();
pShader->FXSetVSFloat(param1Name, m_paramsV, numSamples / 2);
pShader->FXSetPSFloat(param0Name, m_weights, numSamples / 2);
pShader->FXSetPSFloat(clampTCName, &clampTC, 1);
m_passV.Execute();
}
void CGaussianBlurPass::Reset()
{
m_passH.Reset();
m_passV.Reset();
}
@@ -0,0 +1,56 @@
/*
* 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.
#pragma once
#include "FullscreenPass.h"
class CStretchRectPass
{
public:
void Execute(CTexture* pSrcTex, CTexture* pDestTex);
void Reset();
protected:
CFullscreenPass m_pass;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class CGaussianBlurPass
{
public:
CGaussianBlurPass()
: m_scale(FLT_MIN)
, m_distribution(FLT_MIN)
{
}
void Execute(CTexture* pTex, CTexture* pTempTex, float scale, float distribution);
void Reset();
protected:
float GaussianDistribution1D(float x, float rho);
void ComputeParams(int texWidth, int texHeight, int numSamples, float scale, float distribution);
protected:
float m_scale;
float m_distribution;
Vec4 m_paramsH[16];
Vec4 m_paramsV[16];
Vec4 m_weights[16];
CFullscreenPass m_passH;
CFullscreenPass m_passV;
};
@@ -0,0 +1,418 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "DepthOfField.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "../../Common/Textures/TextureManager.h"
#include "Common/RenderCapabilities.h"
namespace
{
const float Pi = (float)M_PI;
float ngon_rad(float theta, float n)
{
return cosf(Pi / n) / cosf(theta - (2 * Pi / n) * floorf((n * theta + PI) / (2 * Pi)));
}
// Shirleys concentric mapping
static Vec2 ToUnitDisk(Vec2 O, float blades, [[maybe_unused]] float fstop)
{
float max_fstops = 8;
float min_fstops = 1;
float normalizedStops = 1.0f;
float phi, r;
const float a = 2 * O.x - 1;
const float b = 2 * O.y - 1;
if (fabs(a) > fabs(b)) // use squares instead of absolute values
{
r = a;
phi = (Pi / 4.0f) * (b / (a + 1e-6f));
}
else
{
r = b;
phi = (Pi / 2.0f) - (Pi / 4.0f) * (a / (b + 1e-6f));
}
float rr = r * powf(ngon_rad(phi, blades), normalizedStops);
rr = fabs(rr) * (rr > 0 ? 1.0f : -1.0f);
return Vec2(rr * cosf(phi + normalizedStops), rr * sinf(phi + normalizedStops));
}
}
void CDepthOfField::UpdateParameters()
{
bool bOverrideActive = IsActive();
bool bUseGameSettings = (m_pUserActive->GetParam()) ? true : false;
float frameTime = clamp_tpl<float>(gEnv->pTimer->GetFrameTime() * 3.0f, 0.0f, 1.0f);
{
float fUserFocusRange = m_pUserFocusRange->GetParam();
float fUserFocusDistance = m_pUserFocusDistance->GetParam();
float fUserBlurAmount = m_pUserBlurAmount->GetParam();
if (bOverrideActive)
{
fUserFocusRange = fUserFocusDistance = fUserBlurAmount = 0.0f;
}
m_fUserFocusRangeCurr += (fUserFocusRange - m_fUserFocusRangeCurr) * frameTime;
m_fUserFocusDistanceCurr += (fUserFocusDistance - m_fUserFocusDistanceCurr) * frameTime;
m_fUserBlurAmountCurr += (fUserBlurAmount - m_fUserBlurAmountCurr) * frameTime;
}
float focalDistance = 0.0f;
float focalRange = 0.0f;
float blurAmount = 0.0f;
/// Override mode: full control over focal distance / range through parameters.
if (bOverrideActive)
{
focalDistance = m_pFocusDistance->GetParam();
focalRange = m_pFocusRange->GetParam();
blurAmount = m_pBlurAmount->GetParam();
}
/// Blend of TOD settings with "user adjustments". Used by flowgraph / trackview.
else if (bUseGameSettings)
{
m_todFocusRange += (m_fUserFocusRangeCurr - m_todFocusRange) * frameTime;
m_todBlurAmount += (m_fUserBlurAmountCurr - m_todBlurAmount) * frameTime;
focalDistance = m_fUserFocusDistanceCurr;
focalRange = m_fUserFocusRangeCurr;
blurAmount = m_fUserBlurAmountCurr;
}
/// Full TOD control.
else
{
float fTodFocusRange = (CRenderer::CV_r_dof == 2) ? m_pTimeOfDayFocusRange->GetParam() : 0;
float fTodBlurAmount = (CRenderer::CV_r_dof == 2) ? m_pTimeOfDayBlurAmount->GetParam() : 0;
m_todFocusRange += (fTodFocusRange * 2.0f - m_todFocusRange) * frameTime;
m_todBlurAmount += (fTodBlurAmount - m_todBlurAmount) * frameTime;
focalDistance = 0.0f;
focalRange = m_todFocusRange;
blurAmount = m_todBlurAmount;
}
float focalMinDistance = -focalRange * 0.5f;
float focalMaxDistance = focalRange * 0.5f;
Vec4 focusParams;
focusParams.x = 1.0f / (focalMaxDistance + 1e-6f);
focusParams.y = -focalDistance / (focalMaxDistance + 1e-6f);
focusParams.z = 1.0f / (focalMinDistance + 1e-6f);
focusParams.w = -focalDistance / (focalMinDistance + 1e-6f);
// Arbitrary scale added for compatibility with deprecated scatter depth of field. Should get removed
// but will break existing content.
blurAmount *= 2.0f;
m_Parameters.m_FocusParams0 = focusParams;
m_Parameters.m_FocusParams1 = Vec4(CRenderer::CV_r_dofMinZ + m_pFocusMinZ->GetParam(), CRenderer::CV_r_dofMinZScale + m_pFocusMinZScale->GetParam(), 0.0f, blurAmount);
m_Parameters.m_bEnabled = blurAmount > 0.001f;
}
void DepthOfFieldPass::UpdatePassConstants(const DepthOfFieldParameters& dofParams)
{
m_PassConstantBuffer->m_focusParams0 = dofParams.m_FocusParams0;
m_PassConstantBuffer->m_focusParams1 = dofParams.m_FocusParams1;
m_PassConstantBuffer.CopyToDevice();
AzRHI::ConstantBuffer* constantBuffer = m_PassConstantBuffer.GetDeviceConstantBuffer().get();
gcpRendD3D->m_DevMan.BindConstantBuffer(eHWSC_Pixel, constantBuffer, eConstantBufferShaderSlot_PerPass);
}
void DepthOfFieldPass::UpdateGatherSubPassConstants(AZ::u32 targetWidth, AZ::u32 targetHeight, AZ::u32 squareTapCount)
{
const float fFNumber = 8;
const float fNumApertureSides = 8;
const float recipTapCount = 1.0f / ((float)squareTapCount - 1.0f);
for (AZ::u32 y = 0; y < squareTapCount; ++y)
{
for (AZ::u32 x = 0; x < squareTapCount; ++x)
{
Vec2 t = Vec2(x * recipTapCount, y * recipTapCount);
Vec2 result = ToUnitDisk(t, fNumApertureSides, fFNumber);
m_GatherSubPassConstantBuffer->m_taps[x + y * squareTapCount] = Vec4(result.x, result.y, 0, 0);
}
}
m_GatherSubPassConstantBuffer->m_ScreenSize = Vec4(
(float)targetWidth,
(float)targetHeight,
1.0f / (float)targetWidth,
1.0f / (float)targetHeight);
m_GatherSubPassConstantBuffer->m_tapCount = Vec4((float)(squareTapCount * squareTapCount), 0, 0, 0);
m_GatherSubPassConstantBuffer.CopyToDevice();
AzRHI::ConstantBuffer* constantBuffer = m_GatherSubPassConstantBuffer.GetDeviceConstantBuffer().get();
gcpRendD3D->m_DevMan.BindConstantBuffer(eHWSC_Pixel, constantBuffer, eConstantBufferShaderSlot_PerSubPass);
}
void DepthOfFieldPass::UpdateMinCoCSubPassConstants(AZ::u32 targetWidth, AZ::u32 targetHeight)
{
m_MinCoCSubPassConstantBuffer->m_ScreenSize = Vec4(
(float)targetWidth,
(float)targetHeight,
1.0f / (float)targetWidth,
1.0f / (float)targetHeight);
m_MinCoCSubPassConstantBuffer.CopyToDevice();
AzRHI::ConstantBuffer* constantBuffer = m_MinCoCSubPassConstantBuffer.GetDeviceConstantBuffer().get();
gcpRendD3D->m_DevMan.BindConstantBuffer(eHWSC_Pixel, constantBuffer, eConstantBufferShaderSlot_PerSubPass);
}
void DepthOfFieldPass::Init()
{
m_PassConstantBuffer.CreateDeviceBuffer();
m_GatherSubPassConstantBuffer.CreateDeviceBuffer();
m_MinCoCSubPassConstantBuffer.CreateDeviceBuffer();
}
void DepthOfFieldPass::Shutdown()
{
}
void DepthOfFieldPass::Reset()
{
}
void DepthOfFieldPass::Execute()
{
PROFILE_SHADER_SCOPE;
PROFILE_LABEL_SCOPE("DOF");
CDepthOfField* depthOfField = (CDepthOfField*)PostEffectMgr()->GetEffect(ePFX_eDepthOfField);
const DepthOfFieldParameters& dofParams = depthOfField->GetParameters();
if (!dofParams.m_bEnabled)
{
return;
}
UpdatePassConstants(dofParams);
gRenDev->m_cEF.mfRefreshSystemShader("DepthOfField", CShaderMan::s_shPostDepthOfField);
uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2]);
CTexture* cocCurrent = SPostEffectsUtils::GetCoCCurrentTarget();
if (CRenderer::CV_r_AntialiasingMode == eAT_TAA)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
gcpRendD3D->SetCullMode(R_CULL_NONE);
// For better blending later.
// We skip this on mobile as to reduce memory bandwidth and fetch from the RT instead using GMEM
bool sampleSceneFromRenderTarget = gcpRendD3D->FX_GetEnabledGmemPath(nullptr) && RenderCapabilities::GetFrameBufferFetchCapabilities().test(RenderCapabilities::FBF_COLOR0);
if (!sampleSceneFromRenderTarget)
{
GetUtils().StretchRect(CTexture::s_ptexHDRTarget, CTexture::s_ptexSceneTarget);
}
CTexture* nearFarLayersTemp[2] = { CTexture::s_ptexHDRTargetScaledTmp[0], CTexture::s_ptexHDRTargetScaledTempRT[0] };
assert(nearFarLayersTemp[0]->GetWidth() == CTexture::s_ptexHDRDofLayers[0]->GetWidth() && nearFarLayersTemp[0]->GetHeight() == CTexture::s_ptexHDRDofLayers[0]->GetHeight());
assert(nearFarLayersTemp[1]->GetWidth() == CTexture::s_ptexHDRDofLayers[1]->GetWidth() && nearFarLayersTemp[1]->GetHeight() == CTexture::s_ptexHDRDofLayers[1]->GetHeight());
assert(nearFarLayersTemp[0]->GetPixelFormat() == CTexture::s_ptexHDRDofLayers[0]->GetPixelFormat() && nearFarLayersTemp[1]->GetPixelFormat() == CTexture::s_ptexHDRDofLayers[1]->GetPixelFormat());
{
// 1st downscale stage
{
PROFILE_LABEL_SCOPE("DOWNSCALE LAYERS");
gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexHDRDofLayers[0], NULL); // near
gcpRendD3D->FX_PushRenderTarget(1, CTexture::s_ptexHDRDofLayers[1], NULL); // far
gcpRendD3D->FX_PushRenderTarget(2, CTexture::s_ptexSceneCoC[0], NULL); // CoC near/far
gcpRendD3D->FX_SetColorDontCareActions(0, true, false);
gcpRendD3D->FX_SetColorDontCareActions(1, true, false);
gcpRendD3D->FX_SetColorDontCareActions(2, true, false);
static CCryNameTSCRC techNameDownscaleDof("DownscaleDof");
GetUtils().ShBeginPass(CShaderMan::s_shPostDepthOfField, techNameDownscaleDof, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
GetUtils().SetTexture(CTexture::s_ptexZTarget, 0, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexHDRTarget, 1, FILTER_LINEAR);
GetUtils().SetTexture(cocCurrent, 2, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(CTexture::s_ptexHDRDofLayers[0]->GetWidth(), CTexture::s_ptexHDRDofLayers[0]->GetHeight());
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_PopRenderTarget(1);
gcpRendD3D->FX_PopRenderTarget(2);
// Avoiding false d3d error (due to deferred rt setup, when ping-pong'ing between RTs we can bump into RTs still bound when binding it as a SRV)
gcpRendD3D->FX_SetActiveRenderTargets();
}
// 2nd downscale stage (tile min CoC)
{
PROFILE_LABEL_SCOPE("MIN COC DOWNSCALE");
uint startingDownscaleIter = 1;
for (uint32 i = startingDownscaleIter; i < MIN_DOF_COC_K; i++)
{
uint32 cocArrayLastElement = i - 1;
if (i == startingDownscaleIter)
{
cocArrayLastElement = 0;
}
gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexSceneCoC[i], NULL); // near
gcpRendD3D->FX_SetColorDontCareActions(0, true, false);
static CCryNameTSCRC techNameTileMinCoC("TileMinCoC");
GetUtils().ShBeginPass(CShaderMan::s_shPostDepthOfField, techNameTileMinCoC, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
UpdateMinCoCSubPassConstants(
CTexture::s_ptexSceneCoC[cocArrayLastElement]->GetWidth(),
CTexture::s_ptexSceneCoC[cocArrayLastElement]->GetHeight());
GetUtils().SetTexture(CTexture::s_ptexSceneCoC[cocArrayLastElement], 0, FILTER_LINEAR);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(CTexture::s_ptexSceneCoC[i]->GetWidth(), CTexture::s_ptexSceneCoC[i]->GetHeight());
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_SetActiveRenderTargets();
}
}
}
{
// 1st gather pass
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(DepthOfField_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
AZ::u32 squareTapCount = 7;
#endif
if (gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
squareTapCount = CRenderer::CV_r_GMEM_DOF_Gather1_Quality;
}
UpdateGatherSubPassConstants(
nearFarLayersTemp[0]->GetWidth(),
nearFarLayersTemp[0]->GetHeight(),
squareTapCount);
PROFILE_LABEL_SCOPE("FAR/NEAR LAYER");
gcpRendD3D->FX_PushRenderTarget(0, nearFarLayersTemp[0], NULL);
gcpRendD3D->FX_PushRenderTarget(1, nearFarLayersTemp[1], NULL);
gcpRendD3D->FX_PushRenderTarget(2, CTexture::s_ptexSceneCoCTemp, NULL);
gcpRendD3D->FX_SetColorDontCareActions(0, true, false);
gcpRendD3D->FX_SetColorDontCareActions(1, true, false);
gcpRendD3D->FX_SetColorDontCareActions(2, true, false);
gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE0];
static CCryNameTSCRC techNameDOF("Dof");
GetUtils().ShBeginPass(CShaderMan::s_shPostDepthOfField, techNameDOF, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
GetUtils().SetTexture(CTexture::s_ptexZTargetScaled, 0, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexHDRDofLayers[0], 1, FILTER_LINEAR);
GetUtils().SetTexture(CTexture::s_ptexHDRDofLayers[1], 2, FILTER_LINEAR);
GetUtils().SetTexture(CTexture::s_ptexSceneCoC[0], 3, FILTER_LINEAR);
GetUtils().SetTexture(CTexture::s_ptexSceneCoC[MIN_DOF_COC_K - 1], 4, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(nearFarLayersTemp[0]->GetWidth(), nearFarLayersTemp[0]->GetHeight());
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(2);
gcpRendD3D->FX_PopRenderTarget(1);
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_SetActiveRenderTargets();
}
// 2nd gather iteration
{
AZ::u32 squareTapCount = 3;
if (gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
squareTapCount = CRenderer::CV_r_GMEM_DOF_Gather2_Quality;
}
UpdateGatherSubPassConstants(
CTexture::s_ptexHDRDofLayers[0]->GetWidth(),
CTexture::s_ptexHDRDofLayers[0]->GetHeight(),
squareTapCount);
PROFILE_LABEL_SCOPE("FAR/NEAR LAYER ITERATION");
gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexHDRDofLayers[0], NULL);
gcpRendD3D->FX_PushRenderTarget(1, CTexture::s_ptexHDRDofLayers[1], NULL);
gcpRendD3D->FX_SetColorDontCareActions(0, true, false);
gcpRendD3D->FX_SetColorDontCareActions(1, true, false);
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
static CCryNameTSCRC techNameDOF("Dof");
GetUtils().ShBeginPass(CShaderMan::s_shPostDepthOfField, techNameDOF, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
GetUtils().SetTexture(nearFarLayersTemp[0], 1, FILTER_LINEAR);
GetUtils().SetTexture(nearFarLayersTemp[1], 2, FILTER_LINEAR);
GetUtils().SetTexture(CTexture::s_ptexSceneCoCTemp, 3, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexSceneCoC[MIN_DOF_COC_K - 1], 4, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(CTexture::s_ptexHDRDofLayers[0]->GetWidth(), CTexture::s_ptexHDRDofLayers[0]->GetHeight());
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(1);
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_SetActiveRenderTargets();
}
// Final composition
{
PROFILE_LABEL_SCOPE("COMPOSITE");
gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexHDRTarget, NULL);
static CCryNameTSCRC techNameCompositeDof("CompositeDof");
GetUtils().ShBeginPass(CShaderMan::s_shPostDepthOfField, techNameCompositeDof, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
GetUtils().SetTexture(CTexture::s_ptexZTarget, 0, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexHDRDofLayers[0], 1, FILTER_LINEAR);
GetUtils().SetTexture(CTexture::s_ptexHDRDofLayers[1], 2, FILTER_LINEAR);
GetUtils().SetTexture(CTextureManager::Instance()->GetNoTexture(), 3, FILTER_LINEAR);
if (!sampleSceneFromRenderTarget)
{
GetUtils().SetTexture(CTexture::s_ptexSceneTarget, 4, FILTER_POINT);
}
GetUtils().SetTexture(cocCurrent, 5, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(CTexture::s_ptexHDRTarget->GetWidth(), CTexture::s_ptexHDRTarget->GetHeight());
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
}
CTexture::s_ptexHDRTarget->SetResolved(true);
gcpRendD3D->FX_SetActiveRenderTargets();
}
gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;
}
@@ -0,0 +1,61 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
#include "Common/PostProcess/PostEffects.h"
#include "Common/TypedConstantBuffer.h"
class DepthOfFieldPass
: public GraphicsPipelinePass
{
public:
virtual ~DepthOfFieldPass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
void UpdatePassConstants(const DepthOfFieldParameters& dofParams);
void UpdateGatherSubPassConstants(AZ::u32 targetWidth, AZ::u32 targetHeight, AZ::u32 squareTapCount);
void UpdateMinCoCSubPassConstants(AZ::u32 targetWidth, AZ::u32 targetHeight);
struct PassConstants
{
Vec4 m_focusParams0;
Vec4 m_focusParams1;
Matrix44 m_reprojection;
};
static const AZ::u32 SquareTapSizeMax = 7;
struct GatherSubPassConstants
{
Vec4 m_ScreenSize;
Vec4 m_taps[SquareTapSizeMax * SquareTapSizeMax];
Vec4 m_tapCount; //x = tapCount y,z,w = unused
};
struct MinCoCSubPassConstants
{
Vec4 m_ScreenSize;
};
CTypedConstantBuffer<PassConstants> m_PassConstantBuffer;
CTypedConstantBuffer<GatherSubPassConstants> m_GatherSubPassConstantBuffer;
CTypedConstantBuffer<MinCoCSubPassConstants> m_MinCoCSubPassConstantBuffer;
};
@@ -0,0 +1,137 @@
/*
* 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.
*
*/
#include "RenderDll_precompiled.h"
#include "FurBendData.h"
#include <AzCore/Math/Matrix4x4.h>
/*static*/ FurBendData& FurBendData::Get()
{
static FurBendData s_instance;
return s_instance;
}
void FurBendData::SetupObject(CRenderObject& renderObject, const SRenderingPassInfo& passInfo)
{
if (passInfo.IsRecursivePass())
{
return;
}
renderObject.m_ObjFlags &= ~FOB_HAS_PREVMATRIX;
// Perhaps use a different distance for fur movement bending?
if (renderObject.m_fDistance < CRenderer::CV_r_MotionBlurMaxViewDist)
{
const AZ::u32 currentFrameId = passInfo.GetMainFrameID();
const uintptr_t objectId = reinterpret_cast<uintptr_t>(renderObject.m_pRenderNode);
auto iter = m_objects.find(objectId);
if (iter != m_objects.end())
{
ObjectParameters* pParams = &iter->second;
// Perhaps use a different threshold for fur movement bending?
const float fThreshold = CRenderer::CV_r_MotionBlurThreshold;
if (!Matrix34::IsEquivalent(pParams->m_worldMatrix, renderObject.m_II.m_Matrix, fThreshold))
{
renderObject.m_ObjFlags |= FOB_HAS_PREVMATRIX;
// Slerp rotation, and lerp translation
// FUTURE: THis will be way more efficient once RenderDll uses AZ Math fully
float fBendBias = CRenderer::CV_r_FurMovementBendingBias; // Could instead retrieve stiffness from material
fBendBias = AZ::GetClamp(fBendBias, 0.0f, 1.0f);
AZ::Vector4 rows[4];
rows[0] = AZ::Vector4::CreateFromFloat4(renderObject.m_II.m_Matrix.GetData());
rows[1] = AZ::Vector4::CreateFromFloat4(renderObject.m_II.m_Matrix.GetData() + 4);
rows[2] = AZ::Vector4::CreateFromFloat4(renderObject.m_II.m_Matrix.GetData() + 8);
rows[3] = AZ::Vector4::CreateAxisW();
AZ::Matrix4x4 currMatrix = AZ::Matrix4x4::CreateFromRows(rows[0], rows[1], rows[2], rows[3]);
rows[0] = AZ::Vector4::CreateFromFloat4(pParams->m_worldMatrix.GetData());
rows[1] = AZ::Vector4::CreateFromFloat4(pParams->m_worldMatrix.GetData() + 4);
rows[2] = AZ::Vector4::CreateFromFloat4(pParams->m_worldMatrix.GetData() + 8);
AZ::Matrix4x4 prevMatrix = AZ::Matrix4x4::CreateFromRows(rows[0], rows[1], rows[2], rows[3]);
// Lerp should really be time-based, not frame-based
currMatrix = AZ::Matrix4x4::CreateInterpolated(prevMatrix, currMatrix, fBendBias);
currMatrix.GetRows(&rows[0], &rows[1], &rows[2], &rows[3]);
float vals[12];
rows[0].StoreToFloat4(&vals[0]);
rows[1].StoreToFloat4(&vals[4]);
rows[2].StoreToFloat4(&vals[8]);
memcpy(pParams->m_worldMatrix.GetData(), vals, sizeof(float) * 12);
pParams->m_updateFrameId = currentFrameId;
pParams->m_pRenderObject = &renderObject;
}
}
else
{
uint32 fillThreadId = passInfo.ThreadID();
m_fillData[fillThreadId].push_back(ObjectMap::value_type(objectId, ObjectParameters(renderObject, renderObject.m_II.m_Matrix, currentFrameId)));
}
}
}
void FurBendData::GetPrevObjToWorldMat(CRenderObject& renderObject, Matrix44A& worldMatrix)
{
if (renderObject.m_ObjFlags & FOB_HAS_PREVMATRIX)
{
const uintptr_t objectId = reinterpret_cast<uintptr_t>(renderObject.m_pRenderNode);
auto iter = m_objects.find(objectId);
if (iter != m_objects.end())
{
worldMatrix = iter->second.m_worldMatrix;
return;
}
}
worldMatrix = renderObject.m_II.m_Matrix;
}
void FurBendData::InsertNewElements()
{
AZ::u32 nThreadID = gRenDev->m_RP.m_nProcessThreadID;
if (!m_fillData[nThreadID].empty())
{
m_fillData[nThreadID].CoalesceMemory();
m_objects.insert(&m_fillData[nThreadID][0], &m_fillData[nThreadID][0] + m_fillData[nThreadID].size());
m_fillData[nThreadID].resize(0);
}
}
void FurBendData::FreeData()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
m_fillData[i].clear();
}
for (size_t i = 0; i < sizeof(m_objects) / sizeof(m_objects[0]); ++i)
{
stl::reconstruct(m_objects[i]);
}
}
void FurBendData::OnBeginFrame()
{
AZ_Assert(!gRenDev->m_pRT || gRenDev->m_pRT->IsMainThread(), "");
const AZ::u32 frameId = gRenDev->GetFrameID(false);
m_objects.erase_if([frameId](const VectorMap<uintptr_t, ObjectParameters >::value_type& object)
{
const AZ::u32 discardThreshold = 60;
return (frameId - object.second.m_updateFrameId) > discardThreshold;
});
}
@@ -0,0 +1,55 @@
/*
* 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.
*
*/
#pragma once
//#include "Common/Renderer.h"
class FurBendData
{
public:
static FurBendData& Get();
void SetupObject(CRenderObject& renderObject, const SRenderingPassInfo& passInfo);
void GetPrevObjToWorldMat(CRenderObject& renderObject, Matrix44A& res);
void InsertNewElements();
void FreeData();
void OnBeginFrame();
private:
struct ObjectParameters
{
ObjectParameters()
: m_pRenderObject(nullptr)
{
}
ObjectParameters(CRenderObject& renderObject, const Matrix34A& worldMatrix, AZ::u32 updateFrameId)
: m_pRenderObject(&renderObject)
, m_updateFrameId(updateFrameId)
, m_worldMatrix(worldMatrix)
{
}
CRenderObject* m_pRenderObject;
AZ::u32 m_updateFrameId;
Matrix34 m_worldMatrix;
//uint32 m_numBones;
//DualQuat* m_pBoneQuatsS;
};
typedef VectorMap<uintptr_t, ObjectParameters > ObjectMap;
ObjectMap m_objects;
CThreadSafeRendererContainer<ObjectMap::value_type> m_fillData[RT_COMMAND_BUF_COUNT];
static FurBendData* s_pInstance;
};
@@ -0,0 +1,255 @@
/*
* 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.
*
*/
#include "RenderDll_precompiled.h"
#include "FurPasses.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
FurPasses* FurPasses::s_pInstance = nullptr;
/*static*/ void FurPasses::InstallInstance()
{
if (s_pInstance == nullptr)
{
s_pInstance = new FurPasses();
}
}
/*static*/ void FurPasses::ReleaseInstance()
{
delete s_pInstance;
s_pInstance = nullptr;
}
/*static*/ FurPasses& FurPasses::GetInstance()
{
AZ_Assert(s_pInstance != nullptr, "FurPasses instance being retrieved before install.");
return *s_pInstance;
}
FurPasses::FurPasses()
: m_furShellPassPercent(0.0f)
{
}
FurPasses::~FurPasses()
{
}
FurPasses::RenderMode FurPasses::GetFurRenderingMode()
{
switch (CRenderer::CV_r_Fur)
{
case 1:
return RenderMode::AlphaBlended;
case 2:
return RenderMode::AlphaTested;
default:
return RenderMode::None;
}
}
bool FurPasses::IsRenderingFur()
{
if (GetFurRenderingMode() == RenderMode::None)
{
return false;
}
uint32 flags = SRendItem::BatchFlags(GetFurRenderList(), gcpRendD3D->m_RP.m_pRLD);
return (flags & FB_FUR) != 0;
}
int FurPasses::GetFurRenderList()
{
return (GetFurRenderingMode() == RenderMode::AlphaBlended) ? EFSLIST_TRANSP : EFSLIST_GENERAL;
}
void FurPasses::ExecuteZPostPass()
{
// This pass renders the outermost fur shell in a 1-in-4 stipple pattern to gather lighting data for fur tips.
// It also performs an additional LinearizeDepth pass to provide the updated depths to the deferred pipeline.
if (IsRenderingFur())
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
{
PROFILE_LABEL_SCOPE("FUR_ZPOST");
rd->FX_ZScene(true, false);
rd->m_RP.m_pRenderFunc = &ZPostRenderFunc;
rd->FX_ProcessRenderList(GetFurRenderList(), FB_FUR, false /*bSetRenderFunc*/);
rd->FX_ZScene(false, false, true);
}
rd->FX_LinearizeDepth(CTexture::s_ptexFurZTarget);
}
}
void FurPasses::ExecuteObliteratePass()
{
// This pass captures the lighting data from HDRTarget to s_ptexFurLightAcc, and then removes the stipples from
// the final target (via a horizontal blur only on the stippled pixels) and depth buffer (direct copy from Z target)
// before beginning the forward shading passes
if (IsRenderingFur())
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
PROFILE_LABEL_SCOPE("FUR_OBLITERATE");
// Copy HDR target so we can use it as an input texture
PostProcessUtils().CopyScreenToTexture(CTexture::s_ptexFurLightAcc);
PostProcessUtils().SetTexture(CTexture::s_ptexFurLightAcc, 0, FILTER_POINT);
// Use Z target rather than fur Z target so that the "true" depth can be retained for forward passes
// Without this, some passes may fail depth tests when they should pass (such as eye rendering)
PostProcessUtils().SetTexture(CTexture::s_ptexZTarget, 1, FILTER_POINT);
rd->m_RP.m_pRenderFunc = &ObliterateRenderFunc;
rd->FX_ProcessRenderList(GetFurRenderList(), FB_FUR, false /*bSetRenderFunc*/);
}
}
void FurPasses::ExecuteFinPass()
{
// This pass renders alpha-tested camera-facing silhouettes of the fur fins. It uses similar logic to the fur shadow pass.
if (IsRenderingFur())
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
PROFILE_LABEL_SCOPE("FUR_FINS");
uint64 nSavedFlags = rd->m_RP.m_FlagsShader_RT;
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_GPU_PARTICLE_TURBULENCE]; // Indicates fin pass
FurPasses::GetInstance().ApplyFurDebugFlags();
rd->m_RP.m_pRenderFunc = &FinRenderFunc;
rd->FX_ProcessRenderList(GetFurRenderList(), FB_FUR, false /*bSetRenderFunc*/);
rd->m_RP.m_FlagsShader_RT = nSavedFlags;
}
}
void FurPasses::ExecuteShellPrepass()
{
// This pass gathers and packs all data required by the shell passes into a single buffer. The RGB channels contain
// the accumulated diffuse and specular lighting (without albedo applied), with the diffuse stored in the upper half of
// the channels, and the specular stored in the lower half. The alpha channel contains the scene depth, to save a
// texture read of the linearized depth buffer.
if (IsRenderingFur())
{
// Skip shell prepass for aux viewports. Shader side, this is indicated by %_RT_HDR_MODE being unset, but since the
// render pass hasn't started yet, we have to instead mimic the check that FX_Start performs to set %_RT_HDR_MODE
CD3D9Renderer* const __restrict rd = gcpRendD3D;
bool hdrMode = (rd->m_RP.m_PersFlags2 & RBPF2_HDR_FP16) && !(rd->m_RP.m_nBatchFilter & (FB_Z));
if (hdrMode)
{
PROFILE_LABEL_SCOPE("FUR_SHELL_PREPASS");
uint64 savedFlags = rd->m_RP.m_FlagsShader_RT;
// Volumetric fog is applied in prepass only if fur is alpha blended; alpha tested fur is drawn before fog
bool useVolumetricFog = CD3D9Renderer::CV_r_VolumetricFog != 0 && GetFurRenderingMode() == RenderMode::AlphaBlended;
if (useVolumetricFog)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_VOLUMETRIC_FOG];
}
static CCryNameTSCRC techFurShellPrepass("FurShellPrepass");
rd->FX_PushRenderTarget(0, CTexture::s_ptexFurPrepass, nullptr);
PostProcessUtils().ShBeginPass(CShaderMan::s_ShaderFur, techFurShellPrepass, FEF_DONTSETSTATES | FEF_DONTSETTEXTURES);
SPostEffectsUtils::SetTexture(CTexture::s_ptexFurLightAcc, 0, FILTER_POINT, 0);
SPostEffectsUtils::SetTexture(CTexture::s_ptexSceneTargetR11G11B10F[0], 1, FILTER_POINT, 0);
SPostEffectsUtils::SetTexture(CTexture::s_ptexSceneDiffuse, 2, FILTER_POINT, 0);
SPostEffectsUtils::SetTexture(CTexture::s_ptexSceneNormalsMap, 3, FILTER_POINT, 0);
SPostEffectsUtils::SetTexture(CTexture::s_ptexSceneSpecular, 4, FILTER_POINT, 0);
SPostEffectsUtils::SetTexture(CTexture::s_ptexFurZTarget, 5, FILTER_POINT, 0);
if (useVolumetricFog)
{
SPostEffectsUtils::SetTexture(CTexture::s_ptexVolumetricFog, 6, FILTER_TRILINEAR, 1);
}
rd->FX_SetState(GS_NODEPTHTEST);
GetUtils().DrawQuadFS(CShaderMan::s_ShaderFur, true /*bOutputCamVec*/, CTexture::s_ptexFurPrepass->GetWidth(), CTexture::s_ptexFurPrepass->GetHeight());
GetUtils().ShEndPass();
rd->FX_PopRenderTarget(0);
rd->m_RP.m_FlagsShader_RT = savedFlags;
}
}
}
void FurPasses::ApplyFurDebugFlags()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (rd->CV_r_FurDebug > 0 && (rd->m_RP.m_FlagsShader_RT & g_HWSR_MaskBit[HWSR_HDR_MODE]) != 0) // Don't apply fur debug flags in aux views
{
if (rd->CV_r_FurDebug & 1)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG0];
}
if (rd->CV_r_FurDebug & 2)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG1];
}
if (rd->CV_r_FurDebug & 4)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG2];
}
if (rd->CV_r_FurDebug & 8)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_DEBUG3];
}
}
}
void FurPasses::SetFurShellPassPercent(float percent)
{
m_furShellPassPercent = AZ::GetClamp(percent, 0.0f, 1.0f);
}
float FurPasses::GetFurShellPassPercent()
{
return m_furShellPassPercent;
}
/*static*/ void FurPasses::ZPostRenderFunc()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
static CCryNameTSCRC techFurZPost("FurZPost");
rd->m_RP.m_pShader->FXSetTechnique(techFurZPost);
rd->FX_FlushShader_General();
}
/*static*/ void FurPasses::ObliterateRenderFunc()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
static CCryNameTSCRC techFurObliterate("FurObliterate");
rd->m_RP.m_pShader->FXSetTechnique(techFurObliterate);
rd->FX_FlushShader_General();
}
/*static*/ void FurPasses::FinRenderFunc()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
static CCryNameTSCRC techFurFins("FurFins");
rd->m_RP.m_pShader->FXSetTechnique(techFurFins);
rd->FX_FlushShader_General();
}
@@ -0,0 +1,60 @@
/*
* 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.
*
*/
#pragma once
class FurPasses
{
public:
static void InstallInstance();
static void ReleaseInstance();
static FurPasses& GetInstance();
enum class RenderMode
{
None,
AlphaBlended,
AlphaTested,
};
// Returns how fur is set up to render
RenderMode GetFurRenderingMode();
// Returns whether the current frame contains render items using fur
bool IsRenderingFur();
// Returns the render list that fur render objects should be placed in
int GetFurRenderList();
void ExecuteZPostPass();
void ExecuteObliteratePass();
void ExecuteFinPass();
void ExecuteShellPrepass();
void ApplyFurDebugFlags();
void SetFurShellPassPercent(float percent);
float GetFurShellPassPercent();
protected:
FurPasses();
~FurPasses();
private:
static FurPasses* s_pInstance; // This (and related singleton functions) should be removed when there is a system in place for managing passes.
static void ZPostRenderFunc();
static void ObliterateRenderFunc();
static void FinRenderFunc();
float m_furShellPassPercent;
};
@@ -0,0 +1,415 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "MotionBlur.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
//////////////////////////////////////////////////////////////////////////
// Old Pipeline Pass
AZStd::unique_ptr<CMotionBlur::ObjectMap> CMotionBlur::m_Objects[CMotionBlur::s_maxObjectBuffers];
CThreadSafeRendererContainer<CMotionBlur::ObjectMap::value_type> CMotionBlur::m_FillData[RT_COMMAND_BUF_COUNT];
void CMotionBlur::GetPrevObjToWorldMat(CRenderObject* renderObject, Matrix44A& worldMatrix)
{
assert(renderObject);
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const int threadId = gRenDev->m_RP.m_nProcessThreadID;
// RTT does not support motion blur yet
if (gRenDev->m_RP.m_TI[threadId].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE)
{
worldMatrix = renderObject->m_II.m_Matrix;
return;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if (renderObject->m_ObjFlags & FOB_HAS_PREVMATRIX)
{
const SRenderObjData* renderObjectData = renderObject->GetObjData();
const uintptr_t objectId = renderObjectData ? renderObjectData->m_uniqueObjectId : 0;
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const AZ::u32 objectIndex = GetPrevBufferIndex();
#else
const AZ::u32 frameId = gRenDev->GetFrameID(false);
const AZ::u32 objectIndex = (frameId - 1) % CMotionBlur::s_maxObjectBuffers;
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
auto it = m_Objects[objectIndex]->find(objectId);
if (it != m_Objects[objectIndex]->end())
{
worldMatrix = it->second.m_worldMatrix;
return;
}
}
worldMatrix = renderObject->m_II.m_Matrix;
}
void CMotionBlur::OnBeginFrame()
{
assert(!gRenDev->m_pRT || gRenDev->m_pRT->IsMainThread());
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const AZ::u32 threadId = gRenDev->m_RP.m_nFillThreadID;
if (gRenDev->m_RP.m_TI[threadId].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE)
{
// RTT does not support motion blur yet in render targets yet
return;
}
const AZ::u32 frameId = gRenDev->GetCameraFrameID();
const AZ::u32 objectIndex = GetCurrentBufferIndex();
#else
const AZ::u32 frameId = gRenDev->GetFrameID(false);
const AZ::u32 objectIndex = frameId % CMotionBlur::s_maxObjectBuffers;
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
m_Objects[objectIndex]->erase_if([frameId](const VectorMap<uintptr_t, MotionBlurObjectParameters >::value_type& object)
{
return (frameId - object.second.m_updateFrameId) > s_discardThreshold;
});
}
void CMotionBlur::InsertNewElements()
{
AZ::u32 nThreadID = gRenDev->m_RP.m_nProcessThreadID;
if (m_FillData[nThreadID].empty())
{
return;
}
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const AZ::u32 nObjFrameWriteID = GetCurrentBufferIndex();
#else
const AZ::u32 nFrameID = gRenDev->GetFrameID(false);
const AZ::u32 nObjFrameWriteID = (nFrameID - 1) % CMotionBlur::s_maxObjectBuffers;
#endif //if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
m_FillData[nThreadID].CoalesceMemory();
m_Objects[nObjFrameWriteID]->insert(&m_FillData[nThreadID][0], &m_FillData[nThreadID][0] + m_FillData[nThreadID].size());
m_FillData[nThreadID].resize(0);
}
void CMotionBlur::FreeData()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
m_FillData[i].clear();
}
for (size_t i = 0; i < CMotionBlur::s_maxObjectBuffers; ++i)
{
// m_Objects is a static object that is initialized in CMotionBlur::CMotionBlur, which is not guaranteed to be called by an application.
// CMotionBlur::FreeData is a static cleanup function that is called regardless if CMotionBlur was created or not, so check to verify
// we have valid data in m_Objects before trying to destruct the containers.
if (m_Objects[i].get())
{
stl::reconstruct((*m_Objects[i]));
}
}
}
bool CD3D9Renderer::FX_MotionVectorGeneration(bool bEnable)
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CV_r_MotionVectors)
{
return false;
}
if (bEnable)
{
GetUtils().Log(" +++ Begin object motion vector generation +++ \n");
// Re-use scene target rendertarget for velocity buffer
RT_SetViewport(0, 0, CTexture::s_ptexSceneTarget->GetWidth(), CTexture::s_ptexSceneTarget->GetHeight());
m_RP.m_PersFlags2 |= RBPF2_MOTIONBLURPASS;
}
else
{
FX_ResetPipe();
gcpRendD3D->RT_SetViewport(0, 0, gcpRendD3D->GetWidth(), gcpRendD3D->GetHeight());
m_RP.m_PersFlags2 &= ~RBPF2_MOTIONBLURPASS;
GetUtils().Log(" +++ End object motion vector generation +++ \n");
}
return true;
}
void CMotionBlur::RenderObjectsVelocity()
{
PROFILE_LABEL_SCOPE("OBJECTS VELOCITY");
auto renderTarget = GetUtils().GetVelocityObjectRT();
auto depthTarget = &gcpRendD3D->m_DepthBufferOrig;
// Make sure the depth target is at least as large as the render target.
// Since the render target lags behind by a frame this might not be the case
// when resolution is changed from higher res to lower res.
if (renderTarget != nullptr && depthTarget != nullptr &&
renderTarget->GetWidth() <= depthTarget->nWidth &&
renderTarget->GetHeight() <= depthTarget->nHeight)
{
// Render object velocities
//The render targets are already in memory for gmem mode
if (!gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
gcpRendD3D->FX_PushRenderTarget(0, renderTarget, depthTarget);
}
uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
int iTempX, iTempY, iWidth, iHeight;
gcpRendD3D->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
const bool bAllowMotionVectors = CRenderer::CV_r_MotionVectors > 0;
if (bAllowMotionVectors)
{
uint32 nBatchMask = 0;
// Check for moving geometry
if (!CRenderer::CV_r_MotionBlurGBufferVelocity)
{
nBatchMask |= SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD);
nBatchMask |= SRendItem::BatchFlags(EFSLIST_SKIN, gRenDev->m_RP.m_pRLD);
}
nBatchMask |= SRendItem::BatchFlags(EFSLIST_TRANSP, gRenDev->m_RP.m_pRLD);
if (nBatchMask & FB_MOTIONBLUR)
{
IRenderElement* pPrevRE = gRenDev->m_RP.m_pRE;
gRenDev->m_RP.m_pRE = NULL;
if (!gcpRendD3D->FX_MotionVectorGeneration(true))
{
return;
}
if (!CRenderer::CV_r_MotionBlurGBufferVelocity)
{
gcpRendD3D->FX_ProcessRenderList(EFSLIST_GENERAL, FB_MOTIONBLUR);
gcpRendD3D->FX_ProcessRenderList(EFSLIST_SKIN, FB_MOTIONBLUR);
}
gcpRendD3D->FX_ProcessRenderList(EFSLIST_TRANSP, FB_MOTIONBLUR);
gcpRendD3D->FX_MotionVectorGeneration(false);
gRenDev->m_RP.m_pRE = pPrevRE;
}
}
gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;
if (!gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
gcpRendD3D->FX_PopRenderTarget(0);
}
}
}
//////////////////////////////////////////////////////////////////////////
// New Pipeline Pass
void CMotionBlurPass::Init()
{
}
void CMotionBlurPass::Shutdown()
{
Reset();
}
void CMotionBlurPass::Reset()
{
m_passMotionBlur.Reset();
m_passCopy.Reset();
m_passPacking.Reset();
m_passTileGen1.Reset();
m_passTileGen2.Reset();
m_passNeighborMax.Reset();
}
float CMotionBlurPass::ComputeMotionScale()
{
static float storedMotionScale = 0.0f;
if (gEnv->pTimer->IsTimerPaused(ITimer::ETIMER_GAME))
{
return storedMotionScale;
}
// The length of the generated motion vectors is proportional to the current time step, so we need
// to rescale the motion vectors to simulate a constant camera exposure time
float exposureTime = 1.0f / std::max(CRenderer::CV_r_MotionBlurShutterSpeed, 1e-6f);
float timeStep = std::max(gEnv->pTimer->GetFrameTime(), 1e-6f);
exposureTime *= gEnv->pTimer->GetTimeScale();
storedMotionScale = exposureTime / timeStep;
return storedMotionScale;
}
void CMotionBlurPass::Execute()
{
// Added a check to make sure we're only running the new pipeline motion blur while the new pipeline is enabled.
if (CRenderer::CV_r_GraphicsPipeline <= 0)
{
return;
}
PROFILE_LABEL_SCOPE("MOTION_BLUR");
CD3D9Renderer* rd = gcpRendD3D;
CShader* pShader = CShaderMan::s_shPostMotionBlur;
int vpX, vpY, vpWidth, vpHeight;
rd->GetViewport(&vpX, &vpY, &vpWidth, &vpHeight);
// Check if DOF is enabled
CDepthOfField* pDofRenderTech = (CDepthOfField*)PostEffectMgr()->GetEffect(ePFX_eDepthOfField);
DepthOfFieldParameters dofParameters = pDofRenderTech->GetParameters();
const bool bGatherDofEnabled = CRenderer::CV_r_dof > 0 && dofParameters.m_bEnabled;
Matrix44A mViewProjPrev = CMotionBlur::GetPrevView();
Matrix44 mViewProj = GetUtils().m_pView;
mViewProjPrev = mViewProjPrev * GetUtils().m_pProj * GetUtils().m_pScaleBias;
mViewProjPrev.Transpose();
CTexture* pVelocityRT = CTexture::s_ptexVelocity;
float tileCountX = (float)CTexture::s_ptexVelocityTiles[1]->GetWidth();
float tileCountY = (float)CTexture::s_ptexVelocityTiles[1]->GetHeight();
static CCryNameR motionBlurParamName("vMotionBlurParams");
int texStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
{
PROFILE_LABEL_SCOPE("PACK VELOCITY");
static CCryNameTSCRC techPackVelocities("PackVelocities");
static CCryNameR viewProjPrevName("mViewProjPrev");
static CCryNameR dirBlurName("vDirectionalBlur");
static CCryNameR radBlurName("vRadBlurParam");
CMotionBlur* pMB = (CMotionBlur*)PostEffectMgr()->GetEffect(ePFX_eMotionBlur);
const float maxRange = 32.0f;
const float amount = clamp_tpl<float>(pMB->m_pRadBlurAmount->GetParam() / maxRange, 0.0f, 1.0f);
const float radius = 1.0f / clamp_tpl<float>(pMB->m_pRadBlurRadius->GetParam(), 1e-6f, 2.0f);
const Vec4 blurDir = pMB->m_pDirectionalBlurVec->GetParamVec4();
const Vec4 dirBlurParam = Vec4(blurDir.x * (maxRange / (float)vpWidth), blurDir.y * (maxRange / (float)vpHeight), (float)vpWidth / (float)vpHeight, 1.0f);
const Vec4 radBlurParam = Vec4(pMB->m_pRadBlurScreenPosX->GetParam() * dirBlurParam.z, pMB->m_pRadBlurScreenPosY->GetParam(), radius * amount, amount);
const bool bRadialBlur = amount + (blurDir.x * blurDir.x) + (blurDir.y * blurDir.y) > 1.0f / (float)vpWidth;
m_passPacking.SetRenderTarget(0, pVelocityRT);
m_passPacking.SetTechnique(pShader, techPackVelocities, bRadialBlur ? g_HWSR_MaskBit[HWSR_SAMPLE0] : 0);
m_passPacking.SetState(GS_NODEPTHTEST);
m_passPacking.SetTextureSamplerPair(0, CTexture::s_ptexZTarget, texStatePoint);
m_passPacking.SetTextureSamplerPair(1, CTexture::s_ptexHDRTarget, texStatePoint);
m_passPacking.SetTextureSamplerPair(2, GetUtils().GetVelocityObjectRT(), texStatePoint);
m_passPacking.SetRequireWorldPos(true);
m_passPacking.BeginConstantUpdate();
mViewProjPrev.Transpose();
pShader->FXSetPSFloat(viewProjPrevName, (Vec4*)mViewProjPrev.GetData(), 4);
pShader->FXSetPSFloat(dirBlurName, &dirBlurParam, 1);
pShader->FXSetPSFloat(radBlurName, &radBlurParam, 1);
const Vec4 motionBlurParams = Vec4(ComputeMotionScale(), 1.0f / tileCountX, 1.0f / tileCountX * CRenderer::CV_r_MotionBlurCameraMotionScale, 0);
pShader->FXSetPSFloat(motionBlurParamName, &motionBlurParams, 1);
m_passPacking.Execute();
}
{
PROFILE_LABEL_SCOPE("VELOCITY TILES");
static CCryNameTSCRC techVelocityTileGen("VelocityTileGen");
static CCryNameTSCRC techTileNeighborhood("VelocityTileNeighborhood");
// Tile generation first pass
{
m_passTileGen1.SetRenderTarget(0, CTexture::s_ptexVelocityTiles[0]);
m_passTileGen1.SetTechnique(pShader, techVelocityTileGen, 0);
m_passTileGen1.SetState(GS_NODEPTHTEST);
m_passTileGen1.SetTextureSamplerPair(0, pVelocityRT, texStatePoint);
m_passTileGen1.BeginConstantUpdate();
Vec4 params = Vec4((float)pVelocityRT->GetWidth(), (float)pVelocityRT->GetHeight(), ceilf((float)gcpRendD3D->GetWidth() / tileCountX), 0);
pShader->FXSetPSFloat(motionBlurParamName, &params, 1);
m_passTileGen1.Execute();
}
// Tile generation second pass
{
m_passTileGen2.SetRenderTarget(0, CTexture::s_ptexVelocityTiles[1]);
m_passTileGen2.SetTechnique(pShader, techVelocityTileGen, 0);
m_passTileGen2.SetState(GS_NODEPTHTEST);
m_passTileGen2.SetTextureSamplerPair(0, CTexture::s_ptexVelocityTiles[0], texStatePoint);
m_passTileGen2.BeginConstantUpdate();
Vec4 params = Vec4((float)CTexture::s_ptexVelocityTiles[0]->GetWidth(), (float)CTexture::s_ptexVelocityTiles[0]->GetHeight(), ceilf((float)gcpRendD3D->GetHeight() / tileCountY), 1);
pShader->FXSetPSFloat(motionBlurParamName, &params, 1);
m_passTileGen2.Execute();
}
// Neighborhood max
{
m_passNeighborMax.SetRenderTarget(0, CTexture::s_ptexVelocityTiles[2]);
m_passNeighborMax.SetTechnique(pShader, techTileNeighborhood, 0);
m_passNeighborMax.SetState(GS_NODEPTHTEST);
m_passNeighborMax.SetTextureSamplerPair(0, CTexture::s_ptexVelocityTiles[1], texStatePoint);
m_passNeighborMax.BeginConstantUpdate();
Vec4 params = Vec4(1.0f / tileCountX, 1.0f / tileCountY, 0, 0);
pShader->FXSetPSFloat(motionBlurParamName, &params, 1);
m_passNeighborMax.Execute();
}
}
{
PROFILE_LABEL_SCOPE("MOTION VECTOR APPLY");
static CCryNameTSCRC techMotionBlur("MotionBlur");
if (bGatherDofEnabled)
{
m_passCopy.Execute(CTexture::s_ptexHDRTarget, CTexture::s_ptexSceneTargetR11G11B10F[0]);
}
uint64 rtMask = 0;
rtMask |= (CRenderer::CV_r_MotionBlurQuality >= 2) ? g_HWSR_MaskBit[HWSR_SAMPLE2] : 0;
rtMask |= (CRenderer::CV_r_MotionBlurQuality == 1) ? g_HWSR_MaskBit[HWSR_SAMPLE1] : 0;
m_passMotionBlur.SetRenderTarget(0, CTexture::s_ptexHDRTarget);
m_passMotionBlur.SetTechnique(pShader, techMotionBlur, rtMask);
m_passMotionBlur.SetState(GS_NODEPTHTEST | GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA);
m_passMotionBlur.SetTextureSamplerPair(0, bGatherDofEnabled ? CTexture::s_ptexSceneTargetR11G11B10F[0] : CTexture::s_ptexHDRTargetPrev, texStateLinear);
m_passMotionBlur.SetTextureSamplerPair(1, pVelocityRT, texStatePoint);
m_passMotionBlur.SetTextureSamplerPair(2, CTexture::s_ptexVelocityTiles[2], texStatePoint);
m_passMotionBlur.BeginConstantUpdate();
Vec4 params = Vec4(1.0f / tileCountX, 1.0f / tileCountY, 0, 0);
pShader->FXSetPSFloat(motionBlurParamName, &params, 1);
m_passMotionBlur.Execute();
}
}
@@ -0,0 +1,42 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
#include "Common/UtilityPasses.h"
// This class is deprecated as it requires r_graphicsPipeline > 0 to function properly, which is not supported on all platforms.
class CMotionBlurPass
: public GraphicsPipelinePass
{
public:
virtual ~CMotionBlurPass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
float ComputeMotionScale();
private:
CFullscreenPass m_passPacking;
CFullscreenPass m_passTileGen1;
CFullscreenPass m_passTileGen2;
CFullscreenPass m_passNeighborMax;
CStretchRectPass m_passCopy;
CFullscreenPass m_passMotionBlur;
};
@@ -0,0 +1,823 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "PostAA.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "DepthOfField.h"
#include "../../Common/Textures/TextureManager.h"
#include <Common/RenderCapabilities.h>
struct TemporalAAParameters
{
TemporalAAParameters() {}
Matrix44 m_reprojection;
// Index ordering
// 5 2 6
// 1 0 3
// 7 4 8
float m_beckmannHarrisFilter[9];
float m_useAntiFlickerFilter;
float m_clampingFactor;
float m_newFrameWeight;
};
bool CPostAA::Preprocess()
{
// Disable PostAA for Dolby mode.
static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby");
int DolbyCvarValue = DolbyCvar ? DolbyCvar->GetIVal() : eDVM_Disabled;
return DolbyCvarValue == eDVM_Disabled;
}
void CPostAA::Render()
{
gcpRendD3D->GetGraphicsPipeline().RenderPostAA();
}
PostAAPass::PostAAPass()
{
AZ::RenderNotificationsBus::Handler::BusConnect();
}
PostAAPass::~PostAAPass()
{
AZ::RenderNotificationsBus::Handler::BusDisconnect();
}
void PostAAPass::Init()
{
m_TextureAreaSMAA = CTexture::ForName("EngineAssets/ScreenSpace/AreaTex.dds", FT_DONT_STREAM, eTF_Unknown);
m_TextureSearchSMAA = CTexture::ForName("EngineAssets/ScreenSpace/SearchTex.dds", FT_DONT_STREAM, eTF_Unknown);
}
void PostAAPass::Shutdown()
{
SAFE_RELEASE(m_TextureAreaSMAA);
SAFE_RELEASE(m_TextureSearchSMAA);
}
void PostAAPass::OnRendererFreeResources(int flags)
{
// If texture resources are about to be freed by the renderer
if (flags & FRR_TEXTURES)
{
// Release the PostAA textures first so they do not leak
Shutdown();
}
}
void PostAAPass::Reset()
{
}
static bool IsTemporalRestartNeeded()
{
// When we are activating a new viewport.
static AZ::s32 s_LastViewportId = -1;
if (gRenDev->m_CurViewportID != s_LastViewportId)
{
s_LastViewportId = gRenDev->m_CurViewportID;
return true;
}
const AZ::s32 StaleFrameThresholdCount = 10;
// When we exceed N frames without rendering TAA (e.g. we toggle it on and off).
static AZ::s32 s_LastFrameCounter = 0;
const bool bIsStale = (GetUtils().m_iFrameCounter - s_LastFrameCounter) > StaleFrameThresholdCount;
s_LastFrameCounter = GetUtils().m_iFrameCounter;
return bIsStale;
}
static float BlackmanHarris(Vec2 uv)
{
return expf(-2.29f * (uv.x * uv.x + uv.y * uv.y));
}
static void BuildTemporalParameters(TemporalAAParameters& temporalAAParameters)
{
Matrix44_tpl<f64> reprojection64;
{
Matrix44_tpl<f64> currViewProjMatrixInverse = Matrix44_tpl<f64>(gRenDev->m_ViewProjNoJitterMatrix).GetInverted();
Matrix44_tpl<f64> prevViewProjMatrix = gRenDev->GetPreviousFrameMatrixSet().m_ViewProjMatrix;
reprojection64 = currViewProjMatrixInverse * prevViewProjMatrix;
Matrix44_tpl<f64> scaleBias1 = Matrix44_tpl<f64>(
0.5, 0, 0, 0,
0, -0.5, 0, 0,
0, 0, 1, 0,
0.5, 0.5, 0, 1);
Matrix44_tpl<f64> scaleBias2 = Matrix44_tpl<f64>(
2.0, 0, 0, 0,
0, -2.0, 0, 0,
0, 0, 1, 0,
-1.0, 1.0, 0, 1);
reprojection64 = scaleBias2 * reprojection64 * scaleBias1;
}
const size_t FILTER_WEIGHT_COUNT = 9;
Vec2 filterWeights[FILTER_WEIGHT_COUNT] =
{
Vec2{ 0.0f, 0.0f },
Vec2{ -1.0f, 0.0f },
Vec2{ 0.0f, -1.0f },
Vec2{ 1.0f, 0.0f },
Vec2{ 0.0f, 1.0f },
Vec2{ -1.0f, -1.0f },
Vec2{ 1.0f, -1.0f },
Vec2{ -1.0f, 1.0f },
Vec2{ 1.0f, 1.0f }
};
const Vec2 temporalJitterOffset(gRenDev->m_TemporalJitterClipSpace.x * 0.5f, gRenDev->m_TemporalJitterClipSpace.y * 0.5f);
for (size_t i = 0; i < FILTER_WEIGHT_COUNT; ++i)
{
temporalAAParameters.m_beckmannHarrisFilter[i] = BlackmanHarris((filterWeights[i] - temporalJitterOffset));
}
temporalAAParameters.m_reprojection = reprojection64;
temporalAAParameters.m_useAntiFlickerFilter = (float)CRenderer::CV_r_AntialiasingTAAUseAntiFlickerFilter;
temporalAAParameters.m_clampingFactor = CRenderer::CV_r_AntialiasingTAAClampingFactor;
temporalAAParameters.m_newFrameWeight = AZStd::max(gRenDev->CV_r_AntialiasingTAANewFrameWeight, FLT_EPSILON);
}
void PostAAPass::RenderTemporalAA(
CTexture* sourceTexture,
CTexture* outputTarget,
const DepthOfFieldParameters& depthOfFieldParameters)
{
CShader* pShader = CShaderMan::s_shPostAA;
PROFILE_LABEL_SCOPE("TAA");
uint64 saveFlags_RT = gRenDev->m_RP.m_FlagsShader_RT;
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]);
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_AntialiasingTAAUseVarianceClamping)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
}
if (CRenderer::CV_r_HDREyeAdaptationMode == 2)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
}
// Filter the CoC's when depth of field is enabled.
if (depthOfFieldParameters.m_bEnabled)
{
gcpRendD3D->FX_PushRenderTarget(2, GetUtils().GetCoCCurrentTarget(), nullptr);
GetUtils().SetTexture(GetUtils().GetCoCHistoryTarget(), 4, FILTER_LINEAR);
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
if (IsTemporalRestartNeeded())
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE3];
}
CTexture* currentTarget = GetUtils().GetTemporalCurrentTarget();
CTexture* historyTarget = GetUtils().GetTemporalHistoryTarget();
gcpRendD3D->FX_PushRenderTarget(0, outputTarget, nullptr);
gcpRendD3D->FX_PushRenderTarget(1, currentTarget, nullptr);
static const CCryNameTSCRC TechNameTAA("TAA");
GetUtils().ShBeginPass(pShader, TechNameTAA, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
Vec4 vHDRSetupParams[5];
gEnv->p3DEngine->GetHDRSetupParams(vHDRSetupParams);
{
TemporalAAParameters temporalAAParameters;
BuildTemporalParameters(temporalAAParameters);
{
const float sharpening = max(0.5f + CRenderer::CV_r_AntialiasingTAASharpening, 0.5f); // Catmull-rom sharpening baseline is 0.5.
static CCryNameR paramName("TemporalParams");
Vec4 temporalParams[4];
temporalParams[0] = Vec4(
temporalAAParameters.m_useAntiFlickerFilter,
temporalAAParameters.m_clampingFactor,
temporalAAParameters.m_newFrameWeight,
sharpening);
temporalParams[1] = Vec4(
0.0f,
0.0f,
0.0f,
temporalAAParameters.m_beckmannHarrisFilter[0]);
temporalParams[2] = Vec4(
temporalAAParameters.m_beckmannHarrisFilter[1],
temporalAAParameters.m_beckmannHarrisFilter[2],
temporalAAParameters.m_beckmannHarrisFilter[3],
temporalAAParameters.m_beckmannHarrisFilter[4]);
temporalParams[3] = Vec4(
temporalAAParameters.m_beckmannHarrisFilter[5],
temporalAAParameters.m_beckmannHarrisFilter[6],
temporalAAParameters.m_beckmannHarrisFilter[7],
temporalAAParameters.m_beckmannHarrisFilter[8]);
pShader->FXSetPSFloat(paramName, (const Vec4*)temporalParams, 4);
}
static CCryNameR szReprojMatrix("ReprojectionMatrix");
pShader->FXSetPSFloat(szReprojMatrix, (Vec4*)temporalAAParameters.m_reprojection.GetData(), 4);
static CCryNameR HDREyeAdaptation("HDREyeAdaptation");
pShader->FXSetPSFloat(HDREyeAdaptation, CRenderer::CV_r_HDREyeAdaptationMode == 2 ? &vHDRSetupParams[4] : &vHDRSetupParams[3], 1);
static CCryNameR DOF_FocusParams0("DOF_FocusParams0");
pShader->FXSetPSFloat(DOF_FocusParams0, &depthOfFieldParameters.m_FocusParams0, 1);
static CCryNameR DOF_FocusParams1("DOF_FocusParams1");
pShader->FXSetPSFloat(DOF_FocusParams1, &depthOfFieldParameters.m_FocusParams1, 1);
}
GetUtils().SetTexture(sourceTexture, 0, FILTER_POINT);
GetUtils().SetTexture(historyTarget, 1, FILTER_LINEAR);
if (CTexture::s_ptexCurLumTexture)
{
if (!gRenDev->m_CurViewportID)
{
GetUtils().SetTexture(CTexture::s_ptexCurLumTexture, 2, FILTER_LINEAR);
}
else
{
GetUtils().SetTexture(CTexture::s_ptexHDRToneMaps[0], 2, FILTER_LINEAR);
}
}
else
{
GetUtils().SetTexture(CTextureManager::Instance()->GetWhiteTexture(), 2, FILTER_LINEAR);
}
GetUtils().SetTexture(GetUtils().GetVelocityObjectRT(), 3, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexZTarget, 5, FILTER_POINT);
D3DShaderResourceView* depthSRV[1] = { gcpRendD3D->m_pZBufferDepthReadOnlySRV };
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
SD3DPostEffectsUtils::DrawFullScreenTri(outputTarget->GetWidth(), outputTarget->GetHeight());
depthSRV[0] = nullptr;
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_PopRenderTarget(1);
if (depthOfFieldParameters.m_bEnabled)
{
gcpRendD3D->FX_PopRenderTarget(2);
}
gcpRendD3D->m_RP.m_PersFlags2 |= RBPF2_NOPOSTAA;
gRenDev->m_RP.m_FlagsShader_RT = saveFlags_RT;
}
void PostAAPass::Execute()
{
PROFILE_LABEL_SCOPE("POST_AA");
PROFILE_SHADER_SCOPE;
uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]);
CTexture* inOutBuffer = CTexture::s_ptexSceneSpecular;
// Slimming GBuffer process is done by encoding normals into format that can fit in only two channels
// and then uses the third extra channel to encode specular's Y channel (in YPbPbr format). The CbCr channels can be
// compressed down to two channels due to requiring only 4 bit prcision for them. This means we can't use the specular
// texture for temporary copies. Thus requiring the need to pick other unused textures to be the replacement.
if (CRenderer::CV_r_SlimGBuffer == 1)
{
if (CRenderer::CV_r_AntialiasingMode == eAT_FXAA || CRenderer::CV_r_AntialiasingMode == eAT_SMAA1TX)
{
inOutBuffer = CTexture::s_ptexSceneDiffuse;
}
else
{
inOutBuffer = CTexture::s_ptexSceneNormalsMap;
}
}
static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby");
const int DolbyCvarValue = DolbyCvar ? DolbyCvar->GetIVal() : eDVM_Disabled;
const bool bDolbyHDRMode = DolbyCvarValue > eDVM_Disabled;
CTexture* currentRT = gcpRendD3D->FX_GetCurrentRenderTarget(0);
if (currentRT == SPostEffectsUtils::AcquireFinalCompositeTarget(bDolbyHDRMode) && CRenderer::CV_r_SkipNativeUpscale)
{
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->RT_SetViewport(0, 0, gcpRendD3D->GetNativeWidth(), gcpRendD3D->GetNativeHeight());
gcpRendD3D->FX_SetRenderTarget(0, gcpRendD3D->GetBackBuffer(), nullptr);
gcpRendD3D->FX_SetActiveRenderTargets();
}
bool useCurrentRTForAAOutput = (CRenderer::CV_r_SkipRenderComposites == 1);
switch (CRenderer::CV_r_AntialiasingMode)
{
case eAT_SMAA1TX:
RenderSMAA(inOutBuffer, &inOutBuffer, useCurrentRTForAAOutput);
break;
case eAT_FXAA:
RenderFXAA(inOutBuffer, &inOutBuffer, useCurrentRTForAAOutput);
break;
case eAT_NOAA:
break;
}
if (!CRenderer::CV_r_SkipRenderComposites)
{
RenderComposites(inOutBuffer);
}
gcpRendD3D->m_RP.m_PersFlags2 |= RBPF2_NOPOSTAA;
CTexture::s_ptexBackBuffer->SetResolved(true);
gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;
}
void PostAAPass::RenderSMAA(CTexture* sourceTexture, CTexture** outputTexture, bool useCurrentRT)
{
CTexture* pEdgesTex = CTexture::s_ptexSceneNormalsMap; // Reusing esram resident target
// Need to use a different temporary texture for edge detection since it is using the normal map
// as inout for slimming GBuffer
if(CRenderer::CV_r_SlimGBuffer == 1)
{
pEdgesTex = CTexture::s_ptexSceneNormalsBent;
}
CTexture* pBlendTex = CTexture::s_ptexSceneDiffuse; // Reusing esram resident target (note that we access this FP16 RT using point filtering - full rate on GCN)
if(CRenderer::CV_r_SlimGBuffer == 1)
{
pBlendTex = CTexture::s_ptexSceneSpecularAccMap;
}
CShader* pShader = CShaderMan::s_shPostAA;
if (pEdgesTex && pBlendTex)
{
PROFILE_LABEL_SCOPE("SMAA1tx");
const int iWidth = gcpRendD3D->GetWidth();
const int iHeight = gcpRendD3D->GetHeight();
////////////////////////////////////////////////////////////////////////////////////////////////
// 1st pass: generate edges texture
{
PROFILE_LABEL_SCOPE("Edge Generation");
gcpRendD3D->FX_ClearTarget(pEdgesTex, Clr_Transparent);
gcpRendD3D->FX_PushRenderTarget(0, pEdgesTex, &gcpRendD3D->m_DepthBufferOrig);
gcpRendD3D->FX_SetActiveRenderTargets();
static CCryNameTSCRC pszLumaEdgeDetectTechName("LumaEdgeDetectionSMAA");
static const CCryNameR pPostAAParams("PostAAParams");
gcpRendD3D->RT_SetViewport(0, 0, iWidth, iHeight);
GetUtils().ShBeginPass(pShader, pszLumaEdgeDetectTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
GetUtils().BeginStencilPrePass(false, true);
GetUtils().SetTexture(sourceTexture, 0, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(iWidth, iHeight);
GetUtils().ShEndPass();
GetUtils().EndStencilPrePass();
gcpRendD3D->FX_PopRenderTarget(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// 2nd pass: generate blend texture
{
PROFILE_LABEL_SCOPE("Blend Weight Generation");
gcpRendD3D->FX_ClearTarget(pBlendTex, Clr_Transparent);
gcpRendD3D->FX_PushRenderTarget(0, pBlendTex, &gcpRendD3D->m_DepthBufferOrig);
gcpRendD3D->FX_SetActiveRenderTargets();
static CCryNameTSCRC pszBlendWeightTechName("BlendWeightSMAA");
GetUtils().ShBeginPass(pShader, pszBlendWeightTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
gcpRendD3D->FX_StencilTestCurRef(true, false);
GetUtils().SetTexture(pEdgesTex, 0, FILTER_LINEAR);
GetUtils().SetTexture(m_TextureAreaSMAA, 1, FILTER_LINEAR);
GetUtils().SetTexture(m_TextureSearchSMAA, 2, FILTER_POINT);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(iWidth, iHeight);
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
}
CTexture* pDstRT = CTexture::s_ptexSceneNormalsMap;
// Need to use a different temporary texture for edge detection since it is using the normal map
// as inout for slimming GBuffer
if (CRenderer::CV_r_SlimGBuffer == 1)
{
pDstRT = pEdgesTex;
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Final pass - blend neighborhood pixels
{
PROFILE_LABEL_SCOPE("Composite");
gcpRendD3D->FX_PushRenderTarget(0, pDstRT, NULL);
gcpRendD3D->FX_SetActiveRenderTargets();
gcpRendD3D->FX_StencilTestCurRef(false);
static CCryNameTSCRC pszBlendNeighborhoodTechName("NeighborhoodBlendingSMAA");
GetUtils().ShBeginPass(pShader, pszBlendNeighborhoodTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
GetUtils().SetTexture(pBlendTex, 0, FILTER_POINT);
GetUtils().SetTexture(sourceTexture, 1, FILTER_LINEAR);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(iWidth, iHeight);
GetUtils().ShEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
}
//////////////////////////////////////////////////////////////////////////
// TEMPORAL SMAA 1TX
{
PROFILE_LABEL_SCOPE("TAA");
CTexture* currentTarget = GetUtils().GetTemporalCurrentTarget();
CTexture* historyTarget = GetUtils().GetTemporalHistoryTarget();
if (useCurrentRT)
{
currentTarget = gcpRendD3D->FX_GetCurrentRenderTarget(0);
}
else
{
gcpRendD3D->FX_PushRenderTarget(0, currentTarget, nullptr);
}
static CCryNameTSCRC TechNameTAA("SMAA_TAA");
GetUtils().ShBeginPass(pShader, TechNameTAA, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
{
TemporalAAParameters temporalAAParameters;
BuildTemporalParameters(temporalAAParameters);
const float sharpening = max(1.0f + CRenderer::CV_r_AntialiasingNonTAASharpening, 1.0f);
static CCryNameR szReprojMatrix("ReprojectionMatrix");
pShader->FXSetPSFloat(szReprojMatrix, (Vec4*)temporalAAParameters.m_reprojection.GetData(), 4);
Vec4 temporalParams(
temporalAAParameters.m_useAntiFlickerFilter,
temporalAAParameters.m_clampingFactor,
temporalAAParameters.m_newFrameWeight,
sharpening);
static CCryNameR paramName("TemporalParams");
pShader->FXSetPSFloat(paramName, &temporalParams, 1);
}
GetUtils().SetTexture(pDstRT, 0, FILTER_POINT);
GetUtils().SetTexture(historyTarget, 1, FILTER_LINEAR);
GetUtils().SetTexture(GetUtils().GetVelocityObjectRT(), 3, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexZTarget, 5, FILTER_POINT);
D3DShaderResourceView* depthSRV[1] = { gcpRendD3D->m_pZBufferDepthReadOnlySRV };
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(currentTarget->GetWidth(), currentTarget->GetHeight());
depthSRV[0] = nullptr;
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
GetUtils().ShEndPass();
if (!useCurrentRT)
{
gcpRendD3D->FX_PopRenderTarget(0);
}
*outputTexture = currentTarget;
}
}
}
void PostAAPass::RenderFXAA(CTexture* sourceTexture, CTexture** outputTexture, bool useCurrentRT)
{
PROFILE_LABEL_SCOPE("FXAA");
CTexture* currentTarget = CTexture::s_ptexSceneNormalsMap;
if (useCurrentRT)
{
currentTarget = gcpRendD3D->FX_GetCurrentRenderTarget(0);
}
else
{
gcpRendD3D->FX_PushRenderTarget(0, currentTarget, nullptr);
}
CShader* pShader = CShaderMan::s_shPostAA;
const f32 fWidthRcp = 1.0f / (float)gcpRendD3D->GetWidth();
const f32 fHeightRcp = 1.0f / (float)gcpRendD3D->GetHeight();
static CCryNameTSCRC TechNameFXAA("FXAA");
GetUtils().ShBeginPass(pShader, TechNameFXAA, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
const Vec4 vRcpFrameOpt(-0.33f * fWidthRcp, -0.33f * fHeightRcp, 0.33f * fWidthRcp, 0.33f * fHeightRcp);// (1.0/sz.xy) * -0.33, (1.0/sz.xy) * 0.33. 0.5 -> softer
const Vec4 vRcpFrameOpt2(-2.0f * fWidthRcp, -2.0f * fHeightRcp, 2.0f * fWidthRcp, 2.0f * fHeightRcp);// (1.0/sz.xy) * -2.0, (1.0/sz.xy) * 2.0
static CCryNameR pRcpFrameOptParam("RcpFrameOpt");
pShader->FXSetPSFloat(pRcpFrameOptParam, &vRcpFrameOpt, 1);
static CCryNameR pRcpFrameOpt2Param("RcpFrameOpt2");
pShader->FXSetPSFloat(pRcpFrameOpt2Param, &vRcpFrameOpt2, 1);
GetUtils().SetTexture(sourceTexture, 0, FILTER_LINEAR);
SD3DPostEffectsUtils::DrawFullScreenTriWPOS(sourceTexture->GetWidth(), sourceTexture->GetHeight());
gcpRendD3D->FX_Commit();
GetUtils().ShEndPass();
if (!useCurrentRT)
{
gcpRendD3D->FX_PopRenderTarget(0);
}
*outputTexture = currentTarget;
}
void PostAAPass::RenderComposites(CTexture* sourceTexture)
{
PROFILE_LABEL_SCOPE("FLARES, GRAIN");
CD3D9Renderer* rd = gcpRendD3D;
rd->FX_SetStencilDontCareActions(0, true, true);
bool isAfterPostProcessBucketEmpty = SRendItem::IsListEmpty(EFSLIST_AFTER_POSTPROCESS, rd->m_RP.m_nProcessThreadID, rd->m_RP.m_pRLD);
bool isAuxGeomEnabled = false;
#if defined(ENABLE_RENDER_AUX_GEOM)
isAuxGeomEnabled = CRenderer::CV_r_enableauxgeom == 1;
#endif
//We may need to preserve the depth buffer in case there is something to render in the EFSLIST_AFTER_POSTPROCESS bucket.
//It could be UI in the 3d world. If the bucket is empty ignore the depth buffer as it is not needed.
//Also check if Auxgeom rendering is enabled in which case we preserve depth buffer.
if (isAfterPostProcessBucketEmpty && !isAuxGeomEnabled)
{
rd->FX_SetDepthDontCareActions(0, true, true);
}
else
{
rd->FX_SetDepthDontCareActions(0, false, false);
}
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3] | g_HWSR_MaskBit[HWSR_SAMPLE5]);
// enable sharpening controlled by r_AntialiasingNonTAASharpening here
// TAA applies sharpening in a different shader stage (TAAGatherHistory)
if (!(gcpRendD3D->FX_GetAntialiasingType() & eAT_TAA_MASK) &&
CRenderer::CV_r_AntialiasingNonTAASharpening > 0.f)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
if (gcpRendD3D->m_RP.m_PersFlags2 & RBPF2_LENS_OPTICS_COMPOSITE)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
if (CRenderer::CV_r_FlaresChromaShift > 0.5f / (float)gcpRendD3D->GetWidth()) // only relevant if bigger than half pixel
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE3];
}
}
if (CRenderer::CV_r_colorRangeCompression)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE4];
}
else
{
gRenDev->m_RP.m_FlagsShader_RT &= ~g_HWSR_MaskBit[HWSR_SAMPLE4];
}
if (!RenderCapabilities::SupportsTextureViews())
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE5];
}
PostProcessUtils().SetSRGBShaderFlags();
static const CCryNameTSCRC TechNameComposites("PostAAComposites");
static const CCryNameTSCRC TechNameDebugMotion("PostAADebugMotion");
CCryNameTSCRC techName = TechNameComposites;
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_MotionVectorsDebug)
{
techName = TechNameDebugMotion;
}
GetUtils().ShBeginPass(CShaderMan::s_shPostAA, techName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
{
STexState texStateLinerSRGB(FILTER_LINEAR, true);
texStateLinerSRGB.m_bSRGBLookup = true;
bool bResolutionScaling = false;
#if defined(CRY_USE_METAL) || defined(ANDROID)
{
const Vec2& vDownscaleFactor = gcpRendD3D->m_RP.m_CurDownscaleFactor;
bResolutionScaling = (vDownscaleFactor.x < .999999f) || (vDownscaleFactor.y < .999999f) == false;
gcpRendD3D->SetCurDownscaleFactor(Vec2(1, 1));
}
#endif
if (!bResolutionScaling)
{
texStateLinerSRGB.SetFilterMode(FILTER_POINT);
}
sourceTexture->Apply(0, CTexture::GetTexState(texStateLinerSRGB));
}
gcpRendD3D->FX_PushWireframeMode(R_SOLID_MODE);
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_MotionVectorsDebug)
{
// This is necessary because the depth target is currently bound, and we are reading from it
// in this pass. Therefore, this pushes the same target without the depth buffer and then pops
// it at the end.
CTexture* texture = gcpRendD3D->FX_GetCurrentRenderTarget(0);
AZ_Assert(texture, "No render target is bound.");
gcpRendD3D->FX_PushRenderTarget(0, texture, nullptr);
gcpRendD3D->FX_SetActiveRenderTargets();
TemporalAAParameters temporalAAParameters;
BuildTemporalParameters(temporalAAParameters);
static CCryNameR szReprojMatrix("ReprojectionMatrix");
CShaderMan::s_shPostAA->FXSetPSFloat(szReprojMatrix, (Vec4*)temporalAAParameters.m_reprojection.GetData(), 4);
GetUtils().SetTexture(GetUtils().GetVelocityObjectRT(), 3, FILTER_POINT);
GetUtils().SetTexture(CTexture::s_ptexZTarget, 5, FILTER_POINT);
D3DShaderResourceView* depthSRV[1] = { gcpRendD3D->m_pZBufferDepthReadOnlySRV };
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
SPostEffectsUtils::DrawFullScreenTri(gcpRendD3D->GetOverlayWidth(), gcpRendD3D->GetOverlayHeight());
depthSRV[0] = nullptr;
gcpRendD3D->m_DevMan.BindSRV(eHWSC_Pixel, depthSRV, 14, 1);
gcpRendD3D->FX_Commit();
gcpRendD3D->FX_PopRenderTarget(0);
gcpRendD3D->FX_SetActiveRenderTargets();
}
else
{
const Vec4 temporalParams(0, 0, 0, max(1.0f + CRenderer::CV_r_AntialiasingNonTAASharpening, 1.0f));
static CCryNameR paramName("TemporalParams");
CShaderMan::s_shPostAA->FXSetPSFloat(paramName, &temporalParams, 1);
CTexture* pLensOpticsComposite = CTexture::s_ptexSceneTargetR11G11B10F[0];
GetUtils().SetTexture(pLensOpticsComposite, 5, FILTER_POINT);
if (gRenDev->m_RP.m_FlagsShader_RT & g_HWSR_MaskBit[HWSR_SAMPLE3])
{
const Vec4 vLensOptics(1.0f, 1.0f, 1.0f, CRenderer::CV_r_FlaresChromaShift);
static CCryNameR pLensOpticsParam("vLensOpticsParams");
CShaderMan::s_shPostAA->FXSetPSFloat(pLensOpticsParam, &vLensOptics, 1);
}
// Apply grain (unfortunately final luminance texture doesn't get its final value baked, so have to replicate entire hdr eye adaption)
{
Vec4 vHDRSetupParams[5];
gEnv->p3DEngine->GetHDRSetupParams(vHDRSetupParams);
CEffectParam* m_pFilterGrainAmount = PostEffectMgr()->GetByName("FilterGrain_Amount");
CEffectParam* m_pFilterArtifactsGrain = PostEffectMgr()->GetByName("FilterArtifacts_Grain");
const float fFiltersGrainAmount = max(m_pFilterGrainAmount->GetParam(), m_pFilterArtifactsGrain->GetParam());
const Vec4 v = Vec4(0, 0, 0, max(fFiltersGrainAmount, max(vHDRSetupParams[1].w, CRenderer::CV_r_HDRGrainAmount)));
static CCryNameR szHDRParam("HDRParams");
CShaderMan::s_shPostAA->FXSetPSFloat(szHDRParam, &v, 1);
static CCryNameR szHDREyeAdaptationParam("HDREyeAdaptation");
CShaderMan::s_shPostAA->FXSetPSFloat(szHDREyeAdaptationParam, &vHDRSetupParams[3], 1);
GetUtils().SetTexture(CTextureManager::Instance()->GetDefaultTexture("FilmGrainMap"), 6, FILTER_POINT, 0);
if (CTexture::s_ptexCurLumTexture)
{
GetUtils().SetTexture(CTexture::s_ptexCurLumTexture, 7, FILTER_POINT);
}
#ifdef CRY_USE_METAL // Metal still expects a bound texture here!
else
{
CTextureManager::Instance()->GetWhiteTexture()->Apply(7, FILTER_POINT);
}
#endif
}
SPostEffectsUtils::DrawFullScreenTri(gcpRendD3D->GetOverlayWidth(), gcpRendD3D->GetOverlayHeight());
}
gcpRendD3D->FX_PopWireframeMode();
GetUtils().ShEndPass();
//UI should be coming in next. Since its in a gem we cant set loadactions in lyshine.
//Hence we are setting it here. Stencil is setup as DoCare for load and store as it gets cleared at the start of UI rendering
rd->FX_SetDepthDontCareActions(0, true, true); //We set this again here as all the actions get reset to conservative settings (do care) after the draw call
rd->FX_SetStencilDontCareActions(0, false, false);
}
void PostAAPass::RenderFinalComposite(CTexture* sourceTexture)
{
if (CShaderMan::s_shPostAA == NULL)
{
return;
}
PROFILE_LABEL_SCOPE("NATIVE_UPSCALE");
gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE5]);
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const bool renderSceneToTexture = (gcpRendD3D->m_RP.m_TI[gcpRendD3D->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE) != 0;
if ((sourceTexture->GetWidth() != gRenDev->GetOverlayWidth() || sourceTexture->GetHeight() != gRenDev->GetOverlayHeight()) && !renderSceneToTexture)
#else
if (sourceTexture->GetWidth() != gRenDev->GetOverlayWidth() || sourceTexture->GetHeight() != gRenDev->GetOverlayHeight())
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
}
if (!RenderCapabilities::SupportsTextureViews())
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE5];
}
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if (CRenderer::CV_r_FinalOutputAlpha == static_cast<int>(AzRTT::AlphaMode::ALPHA_DEPTH_BASED))
{
// enable sampling of depth target for alpha value
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
PostProcessUtils().SetSRGBShaderFlags();
gcpRendD3D->FX_PushWireframeMode(R_SOLID_MODE);
gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
static CCryNameTSCRC pTechName("UpscaleImage");
SPostEffectsUtils::ShBeginPass(CShaderMan::s_shPostAA, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
STexState texStateLinerSRGB(FILTER_LINEAR, true);
texStateLinerSRGB.m_bSRGBLookup = true;
sourceTexture->Apply(0, CTexture::GetTexState(texStateLinerSRGB));
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
if (CRenderer::CV_r_FinalOutputAlpha == static_cast<int>(AzRTT::AlphaMode::ALPHA_DEPTH_BASED))
{
CTexture::s_ptexZTarget->Apply(1, CTexture::GetTexState(STexState(FILTER_POINT, true)));
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
SPostEffectsUtils::DrawFullScreenTri(gcpRendD3D->GetOverlayWidth(), gcpRendD3D->GetOverlayHeight());
SPostEffectsUtils::ShEndPass();
gcpRendD3D->FX_PopWireframeMode();
}
@@ -0,0 +1,45 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
#include "Common/PostProcess/PostEffects.h"
#include <RenderBus.h>
class PostAAPass
: public GraphicsPipelinePass
, AZ::RenderNotificationsBus::Handler
{
public:
PostAAPass();
virtual ~PostAAPass();
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
void RenderFinalComposite(CTexture* sourceTexture);
void RenderTemporalAA(CTexture* sourceTexture, CTexture* outputTarget, const DepthOfFieldParameters& depthOfFieldParameters);
private:
void RenderSMAA(CTexture* sourceTexture, CTexture** outputTexture, bool useCurrentRT);
void RenderFXAA(CTexture* sourceTexture, CTexture** outputTexture, bool useCurrentRT);
void RenderComposites(CTexture* sourceTexture);
void OnRendererFreeResources(int flags) override;
private:
CTexture* m_TextureAreaSMAA;
CTexture* m_TextureSearchSMAA;
};
@@ -0,0 +1,201 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "ScreenSpaceObscurance.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "D3D_SVO.h"
#include "../../Common/Textures/TextureManager.h"
#include "FurPasses.h"
void CScreenSpaceObscurancePass::Init()
{
}
void CScreenSpaceObscurancePass::Shutdown()
{
Reset();
}
void CScreenSpaceObscurancePass::Reset()
{
m_passObscurance.Reset();
m_passFilter.Reset();
m_passAlbedoDownsample0.Reset();
m_passAlbedoDownsample1.Reset();
m_passAlbedoDownsample2.Reset();
m_passAlbedoBlur.Reset();
}
void CScreenSpaceObscurancePass::Execute()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (!CRenderer::CV_r_ssdo)
{
rd->FX_ClearTarget(CTexture::s_ptexSceneNormalsBent, Clr_Median);
return;
}
// Calculate height map AO first
ShadowMapFrustum* pHeightMapFrustum = NULL;
CTexture* pHeightMapAODepth = NULL;
CTexture* pHeightMapAO = NULL;
CDeferredShading::Instance().HeightMapOcclusionPass(pHeightMapFrustum, pHeightMapAODepth, pHeightMapAO);
PROFILE_LABEL_SCOPE("DIRECTIONAL_OCC");
int texStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
int texStatePointWrap = CTexture::GetTexState(STexState(FILTER_POINT, false));
CTexture* pDestRT = CTexture::s_ptexStereoR;
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(ScreenSpaceObscurance_cpp)
#endif
const bool bLowResOutput = (CRenderer::CV_r_ssdoHalfRes == 3);
if (bLowResOutput)
{
pDestRT = CTexture::s_ptexBackBufferScaled[0];
}
// Obscurance generation
{
CShader* pShader = CShaderMan::s_shDeferredShading;
bool isRenderingFur = FurPasses::GetInstance().IsRenderingFur();
uint64 rtMask = 0;
rtMask |= CRenderer::CV_r_ssdoHalfRes ? g_HWSR_MaskBit[HWSR_SAMPLE0] : 0;
rtMask |= pHeightMapFrustum ? g_HWSR_MaskBit[HWSR_SAMPLE1] : 0;
rtMask |= isRenderingFur ? g_HWSR_MaskBit[HWSR_SAMPLE2] : 0;
// Extreme magnification as happening with small FOVs will cause banding issues with half-res depth
if (CRenderer::CV_r_ssdoHalfRes == 2 && RAD2DEG(rd->GetCamera().GetFov()) < 30)
{
rtMask &= ~g_HWSR_MaskBit[HWSR_SAMPLE0];
}
static CCryNameTSCRC tech("DirOccPass");
m_passObscurance.SetRenderTarget(0, pDestRT);
m_passObscurance.SetTechnique(pShader, tech, rtMask);
m_passObscurance.SetState(GS_NODEPTHTEST);
m_passObscurance.SetTextureSamplerPair(0, CTexture::s_ptexSceneNormalsMap, texStatePoint);
m_passObscurance.SetTextureSamplerPair(1, CTexture::s_ptexZTarget, texStatePoint);
m_passObscurance.SetTextureSamplerPair(3, CTextureManager::Instance()->GetDefaultTexture("AOVOJitter"), texStatePointWrap);
m_passObscurance.SetTextureSamplerPair(5, bLowResOutput ? CTexture::s_ptexZTargetScaled2 : CTexture::s_ptexZTargetScaled, texStatePoint);
m_passObscurance.SetTextureSamplerPair(11, pHeightMapAODepth, texStatePoint);
if (isRenderingFur)
{
m_passObscurance.SetTextureSamplerPair(2, CTexture::s_ptexFurZTarget, texStatePoint);
}
m_passObscurance.SetTexture(12, pHeightMapAO);
m_passObscurance.SetRequireWorldPos(true); // TODO: Can be removed after shader changes
m_passObscurance.BeginConstantUpdate();
float radius = CRenderer::CV_r_ssdoRadius / rd->GetViewParameters().fFar;
#if defined(FEATURE_SVO_GI)
if (CSvoRenderer::GetInstance()->IsActive())
{
radius *= CSvoRenderer::GetInstance()->GetSsaoAmount();
}
#endif
static CCryNameR ssdoParamsName("SSDOParams");
Vec4 param1(radius * 0.5f * rd->m_ProjMatrix.m00, radius * 0.5f * rd->m_ProjMatrix.m11,
CRenderer::CV_r_ssdoRadiusMin, CRenderer::CV_r_ssdoRadiusMax);
pShader->FXSetPSFloat(ssdoParamsName, &param1, 1);
static CCryNameR viewspaceParamName("ViewSpaceParams");
Vec4 viewSpaceParam(2.0f / rd->m_ProjMatrix.m00, 2.0f / rd->m_ProjMatrix.m11, -1.0f / rd->m_ProjMatrix.m00, -1.0f / rd->m_ProjMatrix.m11);
pShader->FXSetPSFloat(viewspaceParamName, &viewSpaceParam, 1);
Matrix44A matView = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_cam.GetViewMatrix();
// Adjust the camera matrix so that the camera space will be: +y = down, +z - towards, +x - right
Vec3 zAxis = matView.GetRow(1);
matView.SetRow(1, -matView.GetRow(2));
matView.SetRow(2, zAxis);
float z = matView.m13;
matView.m13 = -matView.m23;
matView.m23 = z;
static CCryNameR camMatrixName("SSDO_CameraMatrix");
pShader->FXSetPSFloat(camMatrixName, (Vec4*)matView.GetData(), 3);
static CCryNameR camMatrixInvName("SSDO_CameraMatrixInv");
matView.Invert();
pShader->FXSetPSFloat(camMatrixInvName, (Vec4*)matView.GetData(), 3);
if (pHeightMapFrustum) // Heightmap AO
{
static CCryNameR paramNameHMAO("HMAO_Params");
Vec4 paramHMAO(CRenderer::CV_r_HeightMapAOAmount, 1.0f / pHeightMapFrustum->nTexSize, 0, 0);
pShader->FXSetPSFloat(paramNameHMAO, &paramHMAO, 1);
}
m_passObscurance.Execute();
}
// Filtering pass
if (CRenderer::CV_r_ssdo != 99)
{
CShader* pShader = rd->m_cEF.s_ShaderShadowBlur;
const int32 sizeX = CTexture::s_ptexZTarget->GetWidth();
const int32 sizeY = CTexture::s_ptexZTarget->GetHeight();
const int32 srcSizeX = pDestRT->GetWidth();
const int32 srcSizeY = pDestRT->GetHeight();
static CCryNameTSCRC tech("SSDO_Blur");
m_passFilter.SetRenderTarget(0, CTexture::s_ptexSceneNormalsBent);
m_passFilter.SetTechnique(pShader, tech, 0);
m_passFilter.SetState(GS_NODEPTHTEST);
m_passFilter.SetTextureSamplerPair(0, pDestRT, texStateLinear);
m_passFilter.SetTextureSamplerPair(1, CTexture::s_ptexZTarget, texStatePoint);
static CCryNameR pixelOffsetName("PixelOffset");
static CCryNameR blurOffsetName("BlurOffset");
static CCryNameR blurKernelName("SSAO_BlurKernel");
m_passFilter.BeginConstantUpdate();
Vec4 v(0, 0, (float)srcSizeX, (float)srcSizeY);
pShader->FXSetVSFloat(pixelOffsetName, &v, 1);
v = Vec4(0.5f / (float)sizeX, 0.5f / (float)sizeY, 1.0f / (float)srcSizeX, 1.0f / (float)srcSizeY);
pShader->FXSetPSFloat(blurOffsetName, &v, 1);
v = Vec4(2.0f / srcSizeX, 0, 2.0f / srcSizeY, 10.0f); // w: weight coef
pShader->FXSetPSFloat(blurKernelName, &v, 1);
m_passFilter.Execute();
}
else // For debugging
{
PostProcessUtils().StretchRect(pDestRT, CTexture::s_ptexSceneNormalsBent);
}
if (CRenderer::CV_r_ssdoColorBleeding)
{
// Generate low frequency scene albedo for color bleeding (convolution not gamma correct but acceptable)
m_passAlbedoDownsample0.Execute(CTexture::s_ptexSceneDiffuse, CTexture::s_ptexBackBufferScaled[0]);
m_passAlbedoDownsample1.Execute(CTexture::s_ptexBackBufferScaled[0], CTexture::s_ptexBackBufferScaled[1]);
m_passAlbedoDownsample2.Execute(CTexture::s_ptexBackBufferScaled[1], CTexture::s_ptexAOColorBleed);
m_passAlbedoBlur.Execute(CTexture::s_ptexAOColorBleed, CTexture::s_ptexBackBufferScaled[0], 1.0f, 4.0f);
}
}
@@ -0,0 +1,39 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
#include "Common/UtilityPasses.h"
class CScreenSpaceObscurancePass
: public GraphicsPipelinePass
{
public:
virtual ~CScreenSpaceObscurancePass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
CFullscreenPass m_passObscurance;
CFullscreenPass m_passFilter;
CStretchRectPass m_passAlbedoDownsample0;
CStretchRectPass m_passAlbedoDownsample1;
CStretchRectPass m_passAlbedoDownsample2;
CGaussianBlurPass m_passAlbedoBlur;
};
@@ -0,0 +1,194 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "ScreenSpaceReflections.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "../../Common/ReverseDepth.h"
void CScreenSpaceReflectionsPass::Init()
{
}
void CScreenSpaceReflectionsPass::Shutdown()
{
}
void CScreenSpaceReflectionsPass::Reset()
{
m_passRaytracing.Reset();
m_passComposition.Reset();
m_passCopy.Reset();
m_passDownsample0.Reset();
m_passDownsample1.Reset();
m_passDownsample2.Reset();
m_passBlur0.Reset();
m_passBlur1.Reset();
m_passBlur2.Reset();
}
void CScreenSpaceReflectionsPass::Execute()
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (!CRenderer::CV_r_SSReflections || !CTexture::s_ptexHDRTarget) // Sketch mode disables HDR rendering
{
return;
}
PROFILE_LABEL_SCOPE("SS_REFLECTIONS");
if (CRenderer::CV_r_SlimGBuffer)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SLIM_GBUFFER];
}
// Store current state
const uint32 prevPersFlags = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags;
Matrix44 mViewProj = rd->m_ViewMatrix * rd->m_ProjMatrix;
if (rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
{
mViewProj = ReverseDepthHelper::Convert(mViewProj);
rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_REVERSE_DEPTH;
rd->GetGraphicsPipeline().UpdatePerViewConstantBuffer();
}
Matrix44 mViewport(0.5f, 0, 0, 0,
0, -0.5f, 0, 0,
0, 0, 1.0f, 0,
0.5f, 0.5f, 0, 1.0f);
const uint32 numGPUs = rd->GetActiveGPUCount();
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const CCamera& camera = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_cam;
const AZ::EntityId cameraID = camera.GetEntityId();
const int frameID = camera.GetFrameUpdateId();
const uint32 prevViewProjID = max((frameID - (int)numGPUs) % MAX_GPU_NUM, 0);
auto iter = m_prevViewProj[prevViewProjID].find(cameraID);
if (iter == m_prevViewProj[prevViewProjID].end())
{
// initialize with the current view projection in case this is a one-off render.
m_prevViewProj[prevViewProjID].insert({cameraID, mViewProj});
}
Matrix44 mViewProjPrev = m_prevViewProj[prevViewProjID][cameraID] * mViewport;
#else
const int frameID = SPostEffectsUtils::m_iFrameCounter;
Matrix44 mViewProjPrev = m_prevViewProj[max((frameID - (int)numGPUs) % MAX_GPU_NUM, 0)] * mViewport;
#endif //if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
int texStateLinear = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
int texStateLinearBorder = CTexture::GetTexState(STexState(FILTER_LINEAR, TADDR_BORDER, TADDR_BORDER, TADDR_BORDER, 0));
CShader* pShader = CShaderMan::s_shDeferredShading;
{
PROFILE_LABEL_SCOPE("SSR_RAYTRACE");
if (CRenderer::CV_r_SlimGBuffer)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SLIM_GBUFFER];
}
CCryNameTSCRC techRaytrace("SSR_Raytrace");
static CCryNameR viewProjName("g_mViewProj");
static CCryNameR viewProjprevName("g_mViewProjPrev");
CTexture* destRT = CRenderer::CV_r_SSReflHalfRes ? CTexture::s_ptexHDRTargetScaled[0] : CTexture::s_ptexHDRTarget;
m_passRaytracing.SetRenderTarget(0, destRT);
m_passRaytracing.SetTechnique(pShader, techRaytrace, rd->m_RP.m_FlagsShader_RT);
m_passRaytracing.SetState(GS_NODEPTHTEST);
m_passRaytracing.SetTextureSamplerPair(0, CTexture::s_ptexZTarget, texStatePoint);
m_passRaytracing.SetTextureSamplerPair(1, CTexture::s_ptexSceneNormalsMap, texStateLinear);
m_passRaytracing.SetTextureSamplerPair(2, CTexture::s_ptexSceneSpecular, texStateLinear);
m_passRaytracing.SetTextureSamplerPair(3, CTexture::s_ptexZTargetScaled, texStatePoint);
m_passRaytracing.SetTextureSamplerPair(4, CTexture::s_ptexHDRTargetPrev, texStateLinearBorder);
m_passRaytracing.SetTextureSamplerPair(5, CTexture::s_ptexHDRMeasuredLuminance[rd->RT_GetCurrGpuID()], texStatePoint);
m_passRaytracing.SetRequireWorldPos(true);
m_passRaytracing.BeginConstantUpdate();
pShader->FXSetPSFloat(viewProjName, (Vec4*)mViewProj.GetData(), 4);
pShader->FXSetPSFloat(viewProjprevName, (Vec4*)mViewProjPrev.GetData(), 4);
m_passRaytracing.Execute();
}
if (!CRenderer::CV_r_SSReflHalfRes)
{
m_passCopy.Execute(CTexture::s_ptexHDRTarget, CTexture::s_ptexHDRTargetScaled[0]);
}
// Convolve sharp reflections
m_passDownsample0.Execute(CTexture::s_ptexHDRTargetScaled[0], CTexture::s_ptexHDRTargetScaled[1]);
m_passBlur0.Execute(CTexture::s_ptexHDRTargetScaled[1], CTexture::s_ptexHDRTargetScaledTempRT[1], 1.0f, 3.0f);
m_passDownsample1.Execute(CTexture::s_ptexHDRTargetScaled[1], CTexture::s_ptexHDRTargetScaled[2]);
m_passBlur1.Execute(CTexture::s_ptexHDRTargetScaled[2], CTexture::s_ptexHDRTargetScaledTempRT[2], 1.0f, 3.0f);
m_passDownsample2.Execute(CTexture::s_ptexHDRTargetScaled[2], CTexture::s_ptexHDRTargetScaled[3]);
m_passBlur2.Execute(CTexture::s_ptexHDRTargetScaled[3], CTexture::s_ptexHDRTargetScaledTempRT[3], 1.0f, 3.0f);
{
PROFILE_LABEL_SCOPE("SSR_COMPOSE");
if (CRenderer::CV_r_SlimGBuffer)
{
rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SLIM_GBUFFER];
}
static CCryNameTSCRC techComposition("SSReflection_Comp");
CTexture* destTex = CTexture::s_ptexHDRTargetScaledTmp[0];
destTex->Unbind();
m_passComposition.SetRenderTarget(0, destTex);
m_passComposition.SetTechnique(pShader, techComposition, rd->m_RP.m_FlagsShader_RT);
m_passComposition.SetState(GS_NODEPTHTEST);
CTexture* smoothnessTex = CTexture::s_ptexSceneSpecular;
// smoothness is encoded in the normal texture for slim GBuffer optimization
if (CRenderer::CV_r_SlimGBuffer)
{
smoothnessTex = CTexture::s_ptexSceneNormalsMap;
}
m_passComposition.SetTextureSamplerPair(0, smoothnessTex, texStateLinear);
m_passComposition.SetTextureSamplerPair(1, CTexture::s_ptexHDRTargetScaled[0], texStateLinear);
m_passComposition.SetTextureSamplerPair(2, CTexture::s_ptexHDRTargetScaled[1], texStateLinear);
m_passComposition.SetTextureSamplerPair(3, CTexture::s_ptexHDRTargetScaled[2], texStateLinear);
m_passComposition.SetTextureSamplerPair(4, CTexture::s_ptexHDRTargetScaled[3], texStateLinear);
m_passComposition.BeginConstantUpdate();
m_passComposition.Execute();
}
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
m_prevViewProj[frameID % MAX_GPU_NUM][cameraID] = mViewProj;
#else
// Update array used for MGPU support
m_prevViewProj[frameID % MAX_GPU_NUM] = mViewProj;
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
// Restore original state
rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags = prevPersFlags;
if (rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
{
uint32 depthState = ReverseDepthHelper::ConvertDepthFunc(rd->m_RP.m_CurState);
rd->FX_SetState(rd->m_RP.m_CurState, rd->m_RP.m_CurAlphaRef, depthState);
rd->GetGraphicsPipeline().UpdatePerViewConstantBuffer();
}
}
@@ -0,0 +1,48 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
#include "Common/UtilityPasses.h"
class CScreenSpaceReflectionsPass
: public GraphicsPipelinePass
{
public:
virtual ~CScreenSpaceReflectionsPass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute();
private:
CFullscreenPass m_passRaytracing;
CFullscreenPass m_passComposition;
CStretchRectPass m_passCopy;
CStretchRectPass m_passDownsample0;
CStretchRectPass m_passDownsample1;
CStretchRectPass m_passDownsample2;
CGaussianBlurPass m_passBlur0;
CGaussianBlurPass m_passBlur1;
CGaussianBlurPass m_passBlur2;
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
// render to texture supports multiple cameras
AZStd::unordered_map<AZ::EntityId, Matrix44> m_prevViewProj[MAX_GPU_NUM];
#else
Matrix44 m_prevViewProj[MAX_GPU_NUM];
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
};
@@ -0,0 +1,91 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "ScreenSpaceSSS.h"
#include "DriverD3D.h"
void CScreenSpaceSSSPass::Init()
{
}
void CScreenSpaceSSSPass::Shutdown()
{
}
void CScreenSpaceSSSPass::Reset()
{
m_passH.Reset();
m_passV.Reset();
}
void CScreenSpaceSSSPass::Execute(CTexture* pIrradianceTex)
{
CD3D9Renderer* const __restrict rd = gcpRendD3D;
if (!CTexture::s_ptexHDRTarget) // Sketch mode disables HDR rendering
{
return;
}
PROFILE_LABEL_SCOPE("SSSSS");
static CCryNameTSCRC techBlur("SSSSS_Blur");
static CCryNameR paramBlur("SSSBlurDir");
static CCryNameR paramViewSpaceParams("ViewSpaceParams");
CShader* pShader = CShaderMan::s_shDeferredShading;
int texStatePoint = CTexture::GetTexState(STexState(FILTER_POINT, true));
Vec4 viewSpaceParams(2.0f / rd->m_ProjMatrix.m00, 2.0f / rd->m_ProjMatrix.m11, -1.0f / rd->m_ProjMatrix.m00, -1.0f / rd->m_ProjMatrix.m11);
float fProjScaleX = 0.5f * rd->m_ProjMatrix.m00;
float fProjScaleY = 0.5f * rd->m_ProjMatrix.m11;
// Horizontal pass
{
m_passH.SetRenderTarget(0, CTexture::s_ptexSceneTargetR11G11B10F[1]);
m_passH.SetTechnique(pShader, techBlur, 0);
m_passH.SetState(GS_NODEPTHTEST);
m_passH.SetTextureSamplerPair(0, pIrradianceTex, texStatePoint);
m_passH.SetTextureSamplerPair(1, CTexture::s_ptexZTarget, texStatePoint);
m_passH.SetTextureSamplerPair(2, CTexture::s_ptexSceneNormalsMap, texStatePoint);
m_passH.SetTextureSamplerPair(3, CTexture::s_ptexSceneDiffuse, texStatePoint);
m_passH.SetTextureSamplerPair(4, CTexture::s_ptexSceneSpecular, texStatePoint);
m_passH.BeginConstantUpdate();
pShader->FXSetPSFloat(paramViewSpaceParams, &viewSpaceParams, 1);
Vec4 blurParam(fProjScaleX, 0, 0, 0);
pShader->FXSetPSFloat(paramBlur, &blurParam, 1);
m_passH.Execute();
}
// Vertical pass
{
m_passV.SetRenderTarget(0, CTexture::s_ptexHDRTarget);
m_passV.SetTechnique(pShader, techBlur, g_HWSR_MaskBit[HWSR_SAMPLE0]);
m_passV.SetState(GS_NODEPTHTEST | GS_BLSRC_ONE | GS_BLDST_ONE);
m_passV.SetTextureSamplerPair(0, CTexture::s_ptexSceneTargetR11G11B10F[1], texStatePoint);
m_passV.SetTextureSamplerPair(1, CTexture::s_ptexZTarget, texStatePoint);
m_passV.SetTextureSamplerPair(2, CTexture::s_ptexSceneNormalsMap, texStatePoint);
m_passV.SetTextureSamplerPair(3, CTexture::s_ptexSceneDiffuse, texStatePoint);
m_passV.SetTextureSamplerPair(4, CTexture::s_ptexSceneSpecular, texStatePoint);
m_passV.SetTextureSamplerPair(5, pIrradianceTex, texStatePoint);
m_passV.BeginConstantUpdate();
pShader->FXSetPSFloat(paramViewSpaceParams, &viewSpaceParams, 1);
Vec4 blurParam(0, fProjScaleY, 0, 0);
pShader->FXSetPSFloat(paramBlur, &blurParam, 1);
m_passV.Execute();
}
}
@@ -0,0 +1,34 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "Common/FullscreenPass.h"
// Screen Space Subsurface Scattering
class CScreenSpaceSSSPass
: public GraphicsPipelinePass
{
public:
virtual ~CScreenSpaceSSSPass() {}
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute(CTexture* pIrradianceTex);
private:
CFullscreenPass m_passH;
CFullscreenPass m_passV;
};
@@ -0,0 +1,622 @@
/*
* 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.
#include "RenderDll_precompiled.h"
#include "StandardGraphicsPipeline.h"
#include "AutoExposure.h"
#include "Bloom.h"
#include "ScreenSpaceObscurance.h"
#include "ScreenSpaceReflections.h"
#include "ScreenSpaceSSS.h"
#include "MotionBlur.h"
#include "DepthOfField.h"
#include "PostAA.h"
#include "VideoRenderPass.h"
#include "Common/TypedConstantBuffer.h"
#include "Common/Textures/TextureHelpers.h"
#include "Common/Include_HLSL_CPP_Shared.h"
#include "MultiLayerAlphaBlendPass.h"
#if defined(FEATURE_SVO_GI)
#include "D3D_SVO.h"
#endif
#include "DriverD3D.h" //for gcpRendD3D
CStandardGraphicsPipeline::CStandardGraphicsPipeline()
{
AZ::RenderNotificationsBus::Handler::BusConnect();
}
CStandardGraphicsPipeline::~CStandardGraphicsPipeline()
{
AZ::RenderNotificationsBus::Handler::BusDisconnect();
}
void CStandardGraphicsPipeline::Init()
{
RegisterPass<CAutoExposurePass>(m_pAutoExposurePass);
RegisterPass<CBloomPass>(m_pBloomPass);
RegisterPass<CScreenSpaceObscurancePass>(m_pScreenSpaceObscurancePass);
RegisterPass<CScreenSpaceReflectionsPass>(m_pScreenSpaceReflectionsPass);
RegisterPass<CScreenSpaceSSSPass>(m_pScreenSpaceSSSPass);
RegisterPass<CMotionBlurPass>(m_pMotionBlurPass);
RegisterPass<DepthOfFieldPass>(m_pDepthOfFieldPass);
RegisterPass<PostAAPass>(m_pPostAAPass);
RegisterPass<VideoRenderPass>(m_pVideoRenderPass);
// default material resources
{
m_pDefaultMaterialResources = CDeviceObjectFactory::GetInstance().CreateResourceSet();
m_pDefaultMaterialResources->SetConstantBuffer(eConstantBufferShaderSlot_PerMaterial, NULL, EShaderStage_AllWithoutCompute);
for (EEfResTextures texType = EFTT_DIFFUSE; texType < EFTT_MAX; texType = EEfResTextures(texType + 1))
{
CTexture* pDefaultTexture = TextureHelpers::LookupTexDefault(texType);
m_pDefaultMaterialResources->SetTexture(texType, pDefaultTexture, SResourceView::DefaultView, EShaderStage_AllWithoutCompute);
}
}
// default extra per instance
{
EShaderStage shaderStages = EShaderStage_Vertex | EShaderStage_Hull | EShaderStage_Domain;
m_pDefaultInstanceExtraResources = CDeviceObjectFactory::GetInstance().CreateResourceSet();
m_pDefaultInstanceExtraResources->SetConstantBuffer(eConstantBufferShaderSlot_SkinQuat, NULL, shaderStages);
m_pDefaultInstanceExtraResources->SetConstantBuffer(eConstantBufferShaderSlot_SkinQuatPrev, NULL, shaderStages);
m_pDefaultInstanceExtraResources->SetBuffer(EReservedTextureSlot_SkinExtraWeights, WrappedDX11Buffer(), shaderStages);
m_pDefaultInstanceExtraResources->SetBuffer(EReservedTextureSlot_AdjacencyInfo, WrappedDX11Buffer(), shaderStages); // shares shader slot with EReservedTextureSlot_PatchID
}
}
void CStandardGraphicsPipeline::OnRendererFreeResources(int flags)
{
// If texture resources are about to be freed by the renderer
if (flags & FRR_TEXTURES)
{
// Release default resources before CTexture::Shutdown is called so they do not leak
m_pDefaultMaterialResources = nullptr;
m_pDefaultInstanceExtraResources = nullptr;
}
}
void CStandardGraphicsPipeline::Shutdown()
{
for (auto& pass : m_passes)
{
pass->Shutdown();
}
m_passes.clear();
m_pDefaultMaterialResources = nullptr;
}
void CStandardGraphicsPipeline::Prepare()
{
AZ_TRACE_METHOD();
for (auto& pass : m_passes)
{
pass->Prepare();
}
}
void CStandardGraphicsPipeline::Execute()
{
}
void CStandardGraphicsPipeline::Reset()
{
for (const auto& pass : m_passes)
{
pass->Reset();
}
}
static const SRenderLight* FindSunLight(SRenderPipeline& renderPipeline)
{
// We explicitly search for the sun because the pipeline sunlight value
// gets reset several times a frame, so it's not guaranteed to exist.
const TArray<SRenderLight>& lights = renderPipeline.m_DLights[renderPipeline.m_nProcessThreadID][SRendItem::m_RecurseLevel[renderPipeline.m_nProcessThreadID]];
for (AZ::u32 i = 0; i < lights.Num(); ++i)
{
const SRenderLight* light = &lights[i];
if (light->m_Flags & DLF_SUN)
{
return light;
}
}
return nullptr;
}
void CStandardGraphicsPipeline::UpdatePerFrameConstantBuffer(const PerFrameParameters& perFrameParams)
{
CD3D9Renderer* renderer = gcpRendD3D;
const PerFrameParameters& perFrameConstants = renderer->m_cEF.m_PF;
SRenderPipeline& RESTRICT_REFERENCE rp = gRenDev->m_RP;
CTypedConstantBuffer<HLSL_PerFrameConstantBuffer> cb(m_PerFrameConstantBuffer);
cb->PerFrame_VolumetricFogParams = perFrameParams.m_VolumetricFogParams;
cb->PerFrame_VolumetricFogRampParams = perFrameParams.m_VolumetricFogRampParams;
cb->PerFrame_VolumetricFogColorGradientBase = perFrameParams.m_VolumetricFogColorGradientBase;
cb->PerFrame_VolumetricFogColorGradientDelta = perFrameParams.m_VolumetricFogColorGradientDelta;
cb->PerFrame_VolumetricFogColorGradientParams = perFrameParams.m_VolumetricFogColorGradientParams;
cb->PerFrame_VolumetricFogColorGradientRadial = perFrameParams.m_VolumetricFogColorGradientRadial;
cb->PerFrame_VolumetricFogSamplingParams = perFrameParams.m_VolumetricFogSamplingParams;
cb->PerFrame_VolumetricFogDistributionParams = perFrameParams.m_VolumetricFogDistributionParams;
cb->PerFrame_VolumetricFogScatteringParams = perFrameParams.m_VolumetricFogScatteringParams;
cb->PerFrame_VolumetricFogScatteringBlendParams = perFrameParams.m_VolumetricFogScatteringBlendParams;
cb->PerFrame_VolumetricFogScatteringColor = perFrameParams.m_VolumetricFogScatteringColor;
cb->PerFrame_VolumetricFogScatteringSecondaryColor = perFrameParams.m_VolumetricFogScatteringSecondaryColor;
cb->PerFrame_VolumetricFogHeightDensityParams = perFrameParams.m_VolumetricFogHeightDensityParams;
cb->PerFrame_VolumetricFogHeightDensityRampParams = perFrameParams.m_VolumetricFogHeightDensityRampParams;
cb->PerFrame_VolumetricFogDistanceParams = perFrameParams.m_VolumetricFogDistanceParams;
cb->PerFrame_VolumetricFogGlobalEnvProbe0 = renderer->GetVolumetricFog().GetGlobalEnvProbeShaderParam0();
cb->PerFrame_VolumetricFogGlobalEnvProbe1 = renderer->GetVolumetricFog().GetGlobalEnvProbeShaderParam1();
#if defined (FEATURE_SVO_GI)
if (auto* svoRenderer = CSvoRenderer::GetInstance())
{
cb->PerFrame_SvoLightingParams = svoRenderer->GetPerFrameShaderParameters();
}
else
{
cb->PerFrame_SvoLightingParams = CSvoRenderer::GetDisabledPerFrameShaderParameters();
}
#endif
const float time = CRenderer::GetRealTime();
cb->PerFrame_Time = Vec4(time, CRenderer::GetElapsedTime(), time - CRenderer::GetElapsedTime(), perFrameParams.m_MidDayIndicator );
const SRenderLight* sunLight = FindSunLight(renderer->m_RP);
if (sunLight)
{
Vec3 sunDirectionNormalized = sunLight->GetPosition().normalized();
cb->PerFrame_SunDirection = Vec4(sunDirectionNormalized, 1.0);
cb->PerFrame_SunColor = Vec4(sunLight->m_Color.r, sunLight->m_Color.g, sunLight->m_Color.b, perFrameParams.m_SunSpecularMultiplier);
}
else
{
cb->PerFrame_SunDirection = Vec4(0.0f);
cb->PerFrame_SunColor = Vec4(0.0f);
}
cb->PerFrame_CloudShadingColorSun = Vec4(perFrameParams.m_CloudShadingColorSun, 0.0f);
cb->PerFrame_CloudShadingColorSky = Vec4(perFrameParams.m_CloudShadingColorSky, 0.0f);
cb->PerFrame_CloudShadowParams = perFrameParams.m_CloudShadowParams;
cb->PerFrame_CloudShadowAnimParams = perFrameParams.m_CloudShadowAnimParams;
cb->PerFrame_CausticsSmoothSunDirection = Vec4(perFrameParams.m_CausticsSunDirection, 0.0f);
cb->PerFrame_DecalZFightingRemedy = Vec4(perFrameParams.m_DecalZFightingRemedy, CD3D9Renderer::CV_r_ssdoAmountDirect);
cb->PerFrame_WaterLevel = Vec4(perFrameParams.m_WaterLevel, 0.0f);
cb->PerFrame_HDRParams = perFrameParams.m_HDRParams;
{
auto& stereoRenderer = renderer->GetS3DRend();
cb->PerFrame_StereoParams = Vec4(
stereoRenderer.GetMaxSeparationScene() * (stereoRenderer.GetStatus() == IStereoRenderer::Status::kRenderingFirstEye ? 1 : -1),
stereoRenderer.GetZeroParallaxPlaneDist(),
stereoRenderer.GetNearGeoShift(),
stereoRenderer.GetNearGeoScale());
}
cb->PerFrame_RandomParams = Vec4(cry_random(0.0f, 1.0f), cry_random(0.0f, 1.0f), cry_random(0.0f, 1.0f), cry_random(0.0f, 1.0f));
cb->PerFrame_MultiLayerAlphaBlendLayerData.x = MultiLayerAlphaBlendPass::GetInstance().GetLayerCount();
m_PerFrameConstantBuffer = cb.GetDeviceConstantBuffer();
cb.CopyToDevice();
}
void CStandardGraphicsPipeline::BindPerFrameConstantBuffer()
{
auto& deviceManager = gcpRendD3D->m_DevMan;
AzRHI::ConstantBuffer* perFrame = GetPerFrameConstantBuffer().get();
deviceManager.BindConstantBuffer(eHWSC_Vertex, perFrame, eConstantBufferShaderSlot_PerFrame);
deviceManager.BindConstantBuffer(eHWSC_Geometry, perFrame, eConstantBufferShaderSlot_PerFrame);
deviceManager.BindConstantBuffer(eHWSC_Hull, perFrame, eConstantBufferShaderSlot_PerFrame);
deviceManager.BindConstantBuffer(eHWSC_Domain, perFrame, eConstantBufferShaderSlot_PerFrame);
deviceManager.BindConstantBuffer(eHWSC_Pixel, perFrame, eConstantBufferShaderSlot_PerFrame);
deviceManager.BindConstantBuffer(eHWSC_Compute, perFrame, eConstantBufferShaderSlot_PerFrame);
}
void CStandardGraphicsPipeline::UpdatePerViewConstantBuffer()
{
CD3D9Renderer* pRenderer = gcpRendD3D;
SRenderPipeline& RESTRICT_REFERENCE rp = gRenDev->m_RP;
ViewParameters viewInfo(pRenderer->GetViewParameters(), pRenderer->GetCamera());
viewInfo.bReverseDepth = (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) != 0;
viewInfo.bMirrorCull = (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_MIRRORCULL) != 0;
int vpX, vpY, vpWidth, vpHeight;
pRenderer->GetViewport(&vpX, &vpY, &vpWidth, &vpHeight);
viewInfo.viewport.TopLeftX = float(vpX);
viewInfo.viewport.TopLeftY = float(vpY);
viewInfo.viewport.Width = float(vpWidth);
viewInfo.viewport.Height = float(vpHeight);
viewInfo.downscaleFactor = Vec4(rp.m_CurDownscaleFactor.x, rp.m_CurDownscaleFactor.y, pRenderer->m_PrevViewportScale.x, pRenderer->m_PrevViewportScale.y);
viewInfo.m_ViewMatrix = pRenderer->m_CameraMatrix;
viewInfo.m_ViewProjNoTranslateMatrix = pRenderer->m_ViewProjNoTranslateMatrix;
viewInfo.m_ViewProjNoTranslatePrevMatrix = pRenderer->GetPreviousFrameMatrixSet().m_ViewProjNoTranslateMatrix;
viewInfo.m_ViewProjNoTranslatePrevNearestMatrix = pRenderer->GetPreviousFrameMatrixSet().m_ViewNoTranslateMatrix * pRenderer->m_ProjMatrix;
viewInfo.m_ViewProjMatrix = pRenderer->m_ViewProjMatrix;
viewInfo.m_ViewProjPrevMatrix = pRenderer->GetPreviousFrameMatrixSet().m_ViewProjMatrix;
viewInfo.m_ProjMatrix = pRenderer->m_ProjMatrix;
viewInfo.m_WorldViewPreviousPosition = pRenderer->GetPreviousFrameMatrixSet().m_WorldViewPosition;
if (rp.m_ShadowInfo.m_pCurShadowFrustum && (rp.m_TI[rp.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN))
{
const SRenderPipeline::ShadowInfo& shadowInfo = rp.m_ShadowInfo;
assert(shadowInfo.m_nOmniLightSide >= 0 && shadowInfo.m_nOmniLightSide < OMNI_SIDES_NUM);
CCamera& cam = shadowInfo.m_pCurShadowFrustum->FrustumPlanes[shadowInfo.m_nOmniLightSide];
viewInfo.pFrustumPlanes = cam.GetFrustumPlane(0);
}
else
{
viewInfo.pFrustumPlanes = pRenderer->GetCamera().GetFrustumPlane(0);
}
UpdatePerViewConstantBuffer(viewInfo);
}
void CStandardGraphicsPipeline::UpdatePerViewConstantBuffer(const ViewParameters& viewInfo)
{
if (!gEnv->p3DEngine)
{
return;
}
CD3D9Renderer* pRenderer = gcpRendD3D;
SRenderPipeline& RESTRICT_REFERENCE rp = gRenDev->m_RP;
SThreadInfo& threadInfo = rp.m_TI[rp.m_nProcessThreadID];
const PerFrameParameters& perFrameConstants = threadInfo.m_perFrameParameters;
CTypedConstantBuffer<HLSL_PerViewConstantBuffer> cb(m_PerViewConstantBuffer);
const float time = threadInfo.m_RealTime;
cb->PerView_WorldViewPos = Vec4(viewInfo.viewParameters.vOrigin, viewInfo.bMirrorCull ? -1.0f : 1.0f);
cb->PerView_WorldViewPosPrev = Vec4(viewInfo.m_WorldViewPreviousPosition, 0.0f);
cb->PerView_HPosScale = viewInfo.downscaleFactor;
cb->PerView_ScreenSize = Vec4(viewInfo.viewport.Width,
viewInfo.viewport.Height,
0.5f / (viewInfo.viewport.Width / viewInfo.downscaleFactor.x),
0.5f / (viewInfo.viewport.Height / viewInfo.downscaleFactor.y));
cb->PerView_ViewBasisX = Vec4(viewInfo.viewParameters.vX, 0.0f);
cb->PerView_ViewBasisY = Vec4(viewInfo.viewParameters.vY, 0.0f);
cb->PerView_ViewBasisZ = Vec4(viewInfo.viewParameters.vZ, 0.0f);
cb->PerView_ViewProjZeroMatr = viewInfo.m_ViewProjNoTranslateMatrix.GetTransposed();
cb->PerView_ViewProjZeroMatrPrev = viewInfo.m_ViewProjNoTranslatePrevMatrix.GetTransposed();
cb->PerView_ViewProjZeroMatrPrevNearest = viewInfo.m_ViewProjNoTranslatePrevNearestMatrix.GetTransposed();
cb->PerView_ViewProjMatr = viewInfo.m_ViewProjMatrix.GetTransposed();
cb->PerView_ViewProjMatrPrev = viewInfo.m_ViewProjPrevMatrix.GetTransposed();
cb->PerView_ViewMatr = viewInfo.m_ViewMatrix.GetTransposed();
cb->PerView_ProjMatr = viewInfo.m_ProjMatrix.GetTransposed();
cb->PerView_FogColor = Vec4(threadInfo.m_FS.m_CurColor.toVec3(), perFrameConstants.m_VolumetricFogParams.z);
cb->PerView_AnimGenParams = Vec4(time * 2.0f, time * 0.5f, time * 1.0f, time * 0.125f);
// CV_NearFarClipDist
{
// Note: CV_NearFarClipDist.z is used to put the weapon's depth range into correct relation to the whole scene
// when generating the depth texture in the z pass (_RT_NEAREST)
cb->PerView_NearFarClipDist = Vec4(viewInfo.viewParameters.fNear,
viewInfo.viewParameters.fFar,
viewInfo.viewParameters.fFar / gEnv->p3DEngine->GetMaxViewDistance(),
1.0f / viewInfo.viewParameters.fFar);
}
// PerView_ProjRatio
{
float zn = viewInfo.viewParameters.fNear;
float zf = viewInfo.viewParameters.fFar;
float hfov = viewInfo.camera.GetHorizontalFov();
cb->PerView_ProjRatio.x = viewInfo.bReverseDepth ? zn / (zn - zf) : zf / (zf - zn);
cb->PerView_ProjRatio.y = viewInfo.bReverseDepth ? zn / (zf - zn) : zn / (zn - zf);
cb->PerView_ProjRatio.z = 1.0f / hfov;
cb->PerView_ProjRatio.w = 1.0f;
if (gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
//For gmem the depth values are not in linear space.
cb->PerView_ProjRatio.w = 1.0f / zf;
}
}
// PerView_NearestScaled
{
float zn = DRAW_NEAREST_MIN;
float zf = CRenderer::CV_r_DrawNearFarPlane;
float nearZRange = CRenderer::CV_r_DrawNearZRange;
float camScale = pRenderer->CV_r_DrawNearFarPlane / gEnv->p3DEngine->GetMaxViewDistance();
cb->PerView_NearestScaled.x = viewInfo.bReverseDepth ? 1.0f - zf / (zf - zn) * nearZRange : zf / (zf - zn) * nearZRange;
cb->PerView_NearestScaled.y = viewInfo.bReverseDepth ? zn / (zf - zn) * nearZRange * camScale : zn / (zn - zf) * nearZRange * camScale;
cb->PerView_NearestScaled.z = viewInfo.bReverseDepth ? 1.0f - (nearZRange - 0.001f) : nearZRange - 0.001f;
cb->PerView_NearestScaled.w = 1.0f;
if (gcpRendD3D->FX_GetEnabledGmemPath(nullptr))
{
cb->PerView_NearestScaled.w = 1.0f / pRenderer->CV_r_DrawNearFarPlane;
}
}
// PerView_TessInfo
{
// We want to obtain the edge length in pixels specified by CV_r_tessellationtrianglesize
// Therefore the tess factor would depend on the viewport size and CV_r_tessellationtrianglesize
static const ICVar* pCV_e_TessellationMaxDistance(gEnv->pConsole->GetCVar("e_TessellationMaxDistance"));
assert(pCV_e_TessellationMaxDistance);
const float hfov = viewInfo.camera.GetHorizontalFov();
cb->PerView_TessellationParams.x = sqrtf(float(viewInfo.viewport.Width * viewInfo.viewport.Height)) / (hfov * pRenderer->CV_r_tessellationtrianglesize);
cb->PerView_TessellationParams.y = pRenderer->CV_r_displacementfactor;
cb->PerView_TessellationParams.z = pCV_e_TessellationMaxDistance->GetFVal();
cb->PerView_TessellationParams.w = (float)CRenderer::CV_r_ParticlesTessellationTriSize;
}
cb->PerView_FrustumPlaneEquation.SetRow4(0, (Vec4&)viewInfo.pFrustumPlanes[FR_PLANE_RIGHT]);
cb->PerView_FrustumPlaneEquation.SetRow4(1, (Vec4&)viewInfo.pFrustumPlanes[FR_PLANE_LEFT]);
cb->PerView_FrustumPlaneEquation.SetRow4(2, (Vec4&)viewInfo.pFrustumPlanes[FR_PLANE_TOP]);
cb->PerView_FrustumPlaneEquation.SetRow4(3, (Vec4&)viewInfo.pFrustumPlanes[FR_PLANE_BOTTOM]);
const bool bApplySubpixelShift = !(threadInfo.m_PersFlags & (RBPF_DRAWTOTEXTURE | RBPF_SHADOWGEN));
if (bApplySubpixelShift)
{
cb->PerView_JitterParams = gcpRendD3D->m_TemporalJitterClipSpace;
}
else
{
cb->PerView_JitterParams = Vec4(0.0);
}
m_PerViewConstantBuffer = cb.GetDeviceConstantBuffer();
cb.CopyToDevice();
}
void CStandardGraphicsPipeline::BindPerViewConstantBuffer()
{
auto& deviceManager = gcpRendD3D->m_DevMan;
AzRHI::ConstantBuffer* perView = GetPerViewConstantBuffer().get();
deviceManager.BindConstantBuffer(eHWSC_Vertex, perView, eConstantBufferShaderSlot_PerView);
deviceManager.BindConstantBuffer(eHWSC_Geometry, perView, eConstantBufferShaderSlot_PerView);
deviceManager.BindConstantBuffer(eHWSC_Hull, perView, eConstantBufferShaderSlot_PerView);
deviceManager.BindConstantBuffer(eHWSC_Domain, perView, eConstantBufferShaderSlot_PerView);
deviceManager.BindConstantBuffer(eHWSC_Pixel, perView, eConstantBufferShaderSlot_PerView);
deviceManager.BindConstantBuffer(eHWSC_Compute, perView, eConstantBufferShaderSlot_PerView);
}
void CStandardGraphicsPipeline::UpdatePerShadowConstantBuffer(const ShadowParameters& params)
{
CD3D9Renderer* renderer = gcpRendD3D;
const SRenderPipeline& renderPipeline = renderer->m_RP;
const auto& shadowFrustum = *params.m_ShadowFrustum;
CTypedConstantBuffer<HLSL_PerSubPassConstantBuffer_ShadowGen> cb(m_PerShadowConstantBuffer);
cb->PerShadow_FrustumInfo = Vec4(
shadowFrustum.fNearDist,
shadowFrustum.m_eFrustumType != ShadowMapFrustum::e_HeightMapAO ? shadowFrustum.fFarDist : 1.f,
0.0f,
0.0f);
cb->PerShadow_LightPos = Vec4(params.m_ShadowFrustum->vLightSrcRelPos + params.m_ShadowFrustum->vProjTranslation, 0);
cb->PerShadow_ViewPos = Vec4(params.m_ViewerPos, 0);
const float UNUSED = 0.0f;
cb->PerShadow_BiasInfo = Vec4(shadowFrustum.fDepthSlopeBias, UNUSED, UNUSED, UNUSED);
m_PerShadowConstantBuffer = cb.GetDeviceConstantBuffer();
cb.CopyToDevice();
}
void CStandardGraphicsPipeline::ResetRenderState()
{
CD3D9Renderer* rd = gcpRendD3D;
rd->m_nCurStateRS = (uint32) - 1;
rd->m_nCurStateBL = (uint32) - 1;
rd->m_nCurStateDP = (uint32) - 1;
rd->ResetToDefault();
rd->FX_SetState(0, 0, 0xFFFFFFFF);
rd->D3DSetCull(eCULL_Back);
rd->m_bViewportDirty = true;
rd->m_CurViewport = SViewport();
rd->FX_SetViewport();
rd->m_CurTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
rd->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
#ifdef CRY_USE_DX12
rd->GetDeviceContext().ResetCachedState();
#endif
CHWShader::s_pCurPS = nullptr;
CHWShader::s_pCurVS = nullptr;
CHWShader::s_pCurGS = nullptr;
CHWShader::s_pCurDS = nullptr;
CHWShader::s_pCurHS = nullptr;
CHWShader::s_pCurCS = nullptr;
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->Reset();
}
void CStandardGraphicsPipeline::RenderAutoExposure()
{
m_pAutoExposurePass->Execute();
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderBloom()
{
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->SwitchToNewGraphicsPipeline();
m_pBloomPass->Execute();
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderScreenSpaceObscurance()
{
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->SwitchToNewGraphicsPipeline();
m_pScreenSpaceObscurancePass->Execute();
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderScreenSpaceReflections()
{
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->SwitchToNewGraphicsPipeline();
m_pScreenSpaceReflectionsPass->Execute();
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderScreenSpaceSSS(CTexture* pIrradianceTex)
{
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->SwitchToNewGraphicsPipeline();
m_pScreenSpaceSSSPass->Execute(pIrradianceTex);
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderMotionBlur()
{
CDeviceObjectFactory::GetInstance().GetCoreGraphicsCommandList()->SwitchToNewGraphicsPipeline();
m_pMotionBlurPass->Execute();
ResetRenderState();
}
void CStandardGraphicsPipeline::RenderDepthOfField()
{
m_pDepthOfFieldPass->Execute();
}
void CStandardGraphicsPipeline::RenderTemporalAA(CTexture* sourceTexture, CTexture* outputTarget, const DepthOfFieldParameters& depthOfFieldParameters)
{
m_pPostAAPass->RenderTemporalAA(sourceTexture, outputTarget, depthOfFieldParameters);
}
void CStandardGraphicsPipeline::RenderFinalComposite(CTexture* sourceTexture)
{
m_pPostAAPass->RenderFinalComposite(sourceTexture);
}
void CStandardGraphicsPipeline::RenderPostAA()
{
m_pPostAAPass->Execute();
}
SubpixelJitter::Sample SubpixelJitter::EvaluateSample(AZ::u32 counter, Pattern pattern)
{
static const Vec2 vSSAA2x[2] =
{
Vec2(-0.25f, 0.25f),
Vec2(0.25f, -0.25f)
};
static const Vec2 vSSAA3x[3] =
{
Vec2(-1.0f / 3.0f, -1.0f / 3.0f),
Vec2(1.0f / 3.0f, 0.0f / 3.0f),
Vec2(0.0f / 3.0f, 1.0f / 3.0f)
};
static const Vec2 vSSAA4x[4] =
{
Vec2(-0.125, -0.375), Vec2(0.375, -0.125),
Vec2(-0.375, 0.125), Vec2(0.125, 0.375)
};
static const Vec2 vSSAA8x[8] =
{
Vec2(0.0625, -0.1875), Vec2(-0.0625, 0.1875),
Vec2(0.3125, 0.0625), Vec2(-0.1875, -0.3125),
Vec2(-0.3125, 0.3125), Vec2(-0.4375, -0.0625),
Vec2(0.1875, 0.4375), Vec2(0.4375, -0.4375)
};
static const Vec2 vSGSSAA8x8[8] =
{
Vec2(6.0f / 7.0f, 0.0f / 7.0f) - Vec2(0.5f, 0.5f), Vec2(2.0f / 7.0f, 1.0f / 7.0f) - Vec2(0.5f, 0.5f),
Vec2(4.0f / 7.0f, 2.0f / 7.0f) - Vec2(0.5f, 0.5f), Vec2(0.0f / 7.0f, 3.0f / 7.0f) - Vec2(0.5f, 0.5f),
Vec2(7.0f / 7.0f, 4.0f / 7.0f) - Vec2(0.5f, 0.5f), Vec2(3.0f / 7.0f, 5.0f / 7.0f) - Vec2(0.5f, 0.5f),
Vec2(5.0f / 7.0f, 6.0f / 7.0f) - Vec2(0.5f, 0.5f), Vec2(1.0f / 7.0f, 7.0f / 7.0f) - Vec2(0.5f, 0.5f)
};
// Mip bias value, numbers are the new pixel gradient radius.
static float JitterMipBias[] =
{
0.0f,
log2(0.707f), // 2x
log2(0.5f), // 3x
log2(0.5f), // 4x
log2(0.375f), // 8x
log2(0.375f), // 8x
log2(0.375f), // random
log2(0.375f), // 8x
log2(0.375f) // 8x
};
static_assert(AZ_ARRAY_SIZE(JitterMipBias) == Pattern_Count, "JitterMipBias array does not match jitter pattern enum");
const AZ::u32 clampedJitternPattern = clamp_tpl(AZ::u32(pattern), AZ::u32(Pattern_None), AZ::u32(Pattern_Count) - 1);
Sample sample;
switch (clampedJitternPattern)
{
case Pattern_2x:
sample.m_subpixelOffset = vSSAA2x[counter % 2];
break;
case Pattern_3x:
sample.m_subpixelOffset = vSSAA3x[counter % 3];
break;
case Pattern_4x:
sample.m_subpixelOffset = vSSAA4x[counter % 4];
break;
case Pattern_8x:
sample.m_subpixelOffset = vSSAA8x[counter % 8];
break;
case Pattern_SparseGrid8x:
sample.m_subpixelOffset = vSGSSAA8x8[counter % 8];
break;
case Pattern_Random:
sample.m_subpixelOffset = Vec2(SPostEffectsUtils::srandf(), SPostEffectsUtils::srandf()) * 0.5f;
break;
case Pattern_Halton8x:
sample.m_subpixelOffset = Vec2(SPostEffectsUtils::HaltonSequence(counter % 8, 2) - 0.5f,
SPostEffectsUtils::HaltonSequence(counter % 8, 3) - 0.5f);
break;
case Pattern_HaltonRandom:
sample.m_subpixelOffset = Vec2(SPostEffectsUtils::HaltonSequence(counter % 1024, 2) - 0.5f,
SPostEffectsUtils::HaltonSequence(counter % 1024, 3) - 0.5f);
break;
default:
sample.m_subpixelOffset = Vec2(0, 0);
}
sample.m_mipBias = JitterMipBias[clampedJitternPattern];
return sample;
}
void CStandardGraphicsPipeline::RenderVideo(const AZ::VideoRenderer::DrawArguments& drawArguments)
{
m_pVideoRenderPass->Execute(drawArguments);
}
@@ -0,0 +1,174 @@
/*
* 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.
#pragma once
#include "Common/GraphicsPipeline.h"
#include "Common/GraphicsPipelineStateSet.h"
#include <RenderBus.h>
class CAutoExposurePass;
class CBloomPass;
class CScreenSpaceObscurancePass;
class CScreenSpaceReflectionsPass;
class CScreenSpaceSSSPass;
class CMotionBlurPass;
class DepthOfFieldPass;
class PostAAPass;
class VideoRenderPass;
class CCamera;
struct DepthOfFieldParameters;
enum ERenderableTechnique
{
RS_TECH_GBUFPASS,
RS_TECH_ZPREPASS,
RS_TECH_SHADOWPASS,
RS_TECH_NUM
};
class CStandardGraphicsPipeline
: public CGraphicsPipeline
, AZ::RenderNotificationsBus::Handler
{
public:
CStandardGraphicsPipeline();
virtual ~CStandardGraphicsPipeline();
struct ViewParameters
{
ViewParameters(const CameraViewParameters& params, const CCamera& ccamera)
: viewParameters(params)
, camera(ccamera)
{}
const CameraViewParameters& viewParameters;
const CCamera& camera;
const Plane* pFrustumPlanes;
Matrix44A m_ViewMatrix;
Matrix44A m_ViewProjNoTranslateMatrix;
Matrix44A m_ViewProjNoTranslatePrevMatrix;
Matrix44A m_ViewProjNoTranslatePrevNearestMatrix;
Matrix44A m_ViewProjMatrix;
Matrix44A m_ViewProjPrevMatrix;
Matrix44A m_ProjMatrix;
Vec3 m_WorldViewPreviousPosition;
D3D11_VIEWPORT viewport;
Vec4 downscaleFactor;
bool bReverseDepth : 1;
bool bMirrorCull : 1;
};
struct ShadowParameters
{
const ShadowMapFrustum* m_ShadowFrustum;
AZ::u8 m_OmniLightSideIndex;
Vec3 m_ViewerPos;
};
void Init() override;
void Shutdown() override;
void Prepare() override;
void Execute() override;
void Reset() override;
void UpdatePerViewConstantBuffer();
void UpdatePerViewConstantBuffer(const ViewParameters& viewInfo);
void BindPerViewConstantBuffer();
void UpdatePerShadowConstantBuffer(const ShadowParameters& parameters);
AzRHI::ConstantBufferPtr GetPerShadowConstantBuffer() const
{
return m_PerShadowConstantBuffer;
}
void UpdatePerFrameConstantBuffer(const PerFrameParameters& perFrameParams);
void BindPerFrameConstantBuffer();
AzRHI::ConstantBufferPtr GetPerFrameConstantBuffer() const
{
return m_PerFrameConstantBuffer;
}
void ResetRenderState();
// Partial pipeline functions, will be removed once the entire pipeline is implemented in Execute()
void RenderAutoExposure();
void RenderBloom();
void RenderScreenSpaceObscurance();
void RenderScreenSpaceReflections();
void RenderScreenSpaceSSS(CTexture* pIrradianceTex);
void RenderMotionBlur();
void RenderDepthOfField();
void RenderFinalComposite(CTexture* sourceTexture);
void RenderPostAA();
void RenderTemporalAA(CTexture* sourceTexture, CTexture* outputTarget, const DepthOfFieldParameters& depthOfFieldParameters);
void RenderVideo(const AZ::VideoRenderer::DrawArguments& drawArguments);
AzRHI::ConstantBufferPtr GetPerViewConstantBuffer() const { return m_PerViewConstantBuffer; }
CDeviceResourceSetPtr GetDefaultMaterialResources() const { return m_pDefaultMaterialResources; }
CDeviceResourceSetPtr GetDefaultInstanceExtraResources() const { return m_pDefaultInstanceExtraResources; }
private:
void OnRendererFreeResources(int flags) override;
CAutoExposurePass* m_pAutoExposurePass;
CBloomPass* m_pBloomPass;
CScreenSpaceObscurancePass* m_pScreenSpaceObscurancePass;
CScreenSpaceReflectionsPass* m_pScreenSpaceReflectionsPass;
CScreenSpaceSSSPass* m_pScreenSpaceSSSPass;
CMotionBlurPass* m_pMotionBlurPass;
DepthOfFieldPass* m_pDepthOfFieldPass;
PostAAPass* m_pPostAAPass;
VideoRenderPass* m_pVideoRenderPass;
AzRHI::ConstantBufferPtr m_PerFrameConstantBuffer;
AzRHI::ConstantBufferPtr m_PerViewConstantBuffer;
AzRHI::ConstantBufferPtr m_PerShadowConstantBuffer;
CDeviceResourceSetPtr m_pDefaultMaterialResources;
CDeviceResourceSetPtr m_pDefaultInstanceExtraResources;
};
class SubpixelJitter
{
public:
enum Pattern
{
Pattern_None = 0,
Pattern_2x,
Pattern_3x,
Pattern_4x,
Pattern_8x,
Pattern_SparseGrid8x,
Pattern_Random,
Pattern_Halton8x,
Pattern_HaltonRandom,
Pattern_Count
};
struct Sample
{
float m_mipBias;
Vec2 m_subpixelOffset;
};
static Sample EvaluateSample(AZ::u32 counter, Pattern pattern);
};
@@ -0,0 +1,172 @@
/*
* 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.
*
*/
#include "RenderDll_precompiled.h"
#include "VideoRenderPass.h"
#include <IVideoRenderer.h>
#include "D3DPostProcess.h"
#include "../../Common/Textures/TextureManager.h"
VideoRenderPass::VideoRenderPass()
{
}
VideoRenderPass::~VideoRenderPass()
{
}
void VideoRenderPass::Init()
{
m_samplerState = CTexture::GetTexState(STexState(FILTER_LINEAR, true));
m_passConstants.CreateDeviceBuffer();
}
void VideoRenderPass::Shutdown()
{
}
void VideoRenderPass::Reset()
{
}
void VideoRenderPass::Execute(const AZ::VideoRenderer::DrawArguments& drawArguments)
{
CTexture* outputTexture{};
CTexture* inputTextures[AZ::VideoRenderer::MaxInputTextureCount]{};
// Gather textures and update them with any data passed in
{
auto FindTexture = [](uint32 textureId) -> CTexture*
{
return textureId != 0 ? CTexture::GetByID(textureId) : nullptr;
};
outputTexture = FindTexture(drawArguments.m_textures.m_outputTextureId);
for (uint32 textureIndex = 0; textureIndex < AZ::VideoRenderer::MaxInputTextureCount; textureIndex++)
{
const uint32 inputTextureId = drawArguments.m_textures.m_inputTextureIds[textureIndex];
const void* updateData = drawArguments.m_updateData.m_inputTextureData[textureIndex].m_data;
CTexture* inputTexture = FindTexture(inputTextureId);
if (inputTexture != nullptr)
{
if (updateData != nullptr)
{
const ETEX_Format updataDataFormat = drawArguments.m_updateData.m_inputTextureData[textureIndex].m_dataFormat;
const uint32 textureWidth = inputTexture->GetWidthNonVirtual();
const uint32 textureHeight = inputTexture->GetHeightNonVirtual();
inputTexture->UpdateTextureRegion(reinterpret_cast<const uint8_t*>(updateData), 0, 0, 0, textureWidth, textureHeight, 1, updataDataFormat);
}
inputTextures[textureIndex] = inputTexture;
}
}
}
const bool drawingToBackbuffer = (drawArguments.m_drawingToBackbuffer != 0);
if (outputTexture == nullptr && !drawingToBackbuffer)
{
return;
}
// Update Constants
{
m_passConstants->VideoTexture0Scale = drawArguments.m_textureScales[0];
m_passConstants->VideoTexture1Scale = drawArguments.m_textureScales[1];
m_passConstants->VideoTexture2Scale = drawArguments.m_textureScales[2];
m_passConstants->VideoTexture3Scale = drawArguments.m_textureScales[3];
m_passConstants->VideoColorAdjustment = drawArguments.m_colorAdjustment;
m_passConstants.CopyToDevice();
}
CD3D9Renderer* pRend = gcpRendD3D;
SRenderPipeline& RP = pRend->m_RP;
CShader* pShader = CShaderMan::s_ShaderVideo;
CTexture* pBlackTexture = CTextureManager::Instance()->GetBlackTexture();
// Save the flags for restoring after we execute
const uint64 saveFlagsRT = RP.m_FlagsShader_RT;
RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3]);
// We're using each SAMPLE# runtime flag to signify if a texture input slot is being used.
if (drawArguments.m_textures.m_inputTextureIds[0])
{
RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
}
if (drawArguments.m_textures.m_inputTextureIds[1])
{
RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
}
if (drawArguments.m_textures.m_inputTextureIds[2])
{
RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
if (drawArguments.m_textures.m_inputTextureIds[3])
{
RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE3];
}
// Save the viewport for restoring later.
int origViewportX{}, origViewportY{}, origViewportWidth{}, origViewportHeight{};
pRend->GetViewport(&origViewportX, &origViewportY, &origViewportWidth, &origViewportHeight);
const int drawWidth = drawingToBackbuffer ? pRend->GetOverlayWidth() : outputTexture->GetWidthNonVirtual();
const int drawHeight = drawingToBackbuffer ? pRend->GetOverlayHeight() : outputTexture->GetHeightNonVirtual();
if (!drawingToBackbuffer)
{
pRend->FX_PushRenderTarget(0, outputTexture, nullptr);
pRend->FX_SetActiveRenderTargets();
}
pRend->RT_SetViewport(0, 0, drawWidth, drawHeight);
static CCryNameTSCRC techVideoRender("VideoRender");
GetUtils().ShBeginPass(pShader, techVideoRender, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
pRend->m_DevMan.BindConstantBuffer(eHWSC_Pixel, m_passConstants.GetDeviceConstantBuffer(), 0);
for (int index = 0; index < AZ::VideoRenderer::MaxInputTextureCount; index++)
{
CTexture* const inputTexture = inputTextures[index] ? inputTextures[index] : pBlackTexture;
if (inputTexture)
{
inputTexture->ApplyTexture(index, eHWSC_Pixel, SResourceView::DefaultView);
}
}
CTexture::SetSamplerState(m_samplerState, 0, eHWSC_Pixel);
SPostEffectsUtils::DrawFullScreenTriWPOS(drawWidth, drawHeight);
GetUtils().ShEndPass();
if (!drawingToBackbuffer)
{
pRend->FX_PopRenderTarget(0);
pRend->FX_SetActiveRenderTargets();
}
// Restore the viewport
pRend->RT_SetViewport(origViewportX, origViewportY, origViewportWidth, origViewportHeight);
// Restore the flags we saved earlier
RP.m_FlagsShader_RT = saveFlagsRT;
}
@@ -0,0 +1,45 @@
/*
* 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.
*
*/
#pragma once
#include "Common/GraphicsPipelinePass.h"
#include "TypedConstantBuffer.h"
// Renders video data to a texture. Video data can be provided as any number of texture planes,
// the textures are composited together based on inputs passed in. See IVideoRenderer.h for more information.
class VideoRenderPass
: public GraphicsPipelinePass
{
public:
VideoRenderPass();
~VideoRenderPass();
void Init() override;
void Shutdown() override;
void Reset() override;
void Execute(const AZ::VideoRenderer::DrawArguments& drawArguments);
protected:
struct VideoPassConstants
{
Vec4 VideoTexture0Scale;
Vec4 VideoTexture1Scale;
Vec4 VideoTexture2Scale;
Vec4 VideoTexture3Scale;
Vec4 VideoColorAdjustment;
};
CTypedConstantBuffer<VideoPassConstants> m_passConstants;
int m_samplerState;
};