250 lines
10 KiB
C++
250 lines
10 KiB
C++
|
// This file is part of the FidelityFX SDK.
|
||
|
//
|
||
|
// Copyright (C) 2024 Advanced Micro Devices, Inc.
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
// of this software and associated documentation files(the "Software"), to deal
|
||
|
// in the Software without restriction, including without limitation the rights
|
||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
|
||
|
// copies of the Software, and to permit persons to whom the Software is
|
||
|
// furnished to do so, subject to the following conditions :
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included in
|
||
|
// all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
// THE SOFTWARE.
|
||
|
|
||
|
#include "lensrendermodule.h"
|
||
|
|
||
|
#include "core/backend_interface.h"
|
||
|
#include "core/framework.h"
|
||
|
#include "core/uimanager.h"
|
||
|
#include "render/device.h"
|
||
|
#include "render/dynamicresourcepool.h"
|
||
|
#include "render/profiler.h"
|
||
|
#include "render/uploadheap.h"
|
||
|
|
||
|
using namespace cauldron;
|
||
|
|
||
|
static const char* s_FloatingPointMathOptions[] = {"Use FP32", "Use FP16"};
|
||
|
FfxLensFloatPrecision GetFloatPrecision(int32_t fpMathIndex)
|
||
|
{
|
||
|
std::string floatingPointMath = s_FloatingPointMathOptions[fpMathIndex];
|
||
|
if (floatingPointMath == "Use FP16")
|
||
|
return FFX_LENS_FLOAT_PRECISION_16BIT;
|
||
|
else if (floatingPointMath == "Use FP32")
|
||
|
return FFX_LENS_FLOAT_PRECISION_32BIT;
|
||
|
else
|
||
|
{
|
||
|
// Unhandled float precision value.
|
||
|
CAULDRON_ASSERT(false);
|
||
|
}
|
||
|
return FFX_LENS_FLOAT_PRECISION_COUNT;
|
||
|
}
|
||
|
|
||
|
static uint32_t CalcGrainSeed(double deltaTime, double seedUpdateRate)
|
||
|
{
|
||
|
// Update seed for grain at fixed time intervals
|
||
|
static uint32_t seedCtr = 0;
|
||
|
static double timeCtr = 0.0;
|
||
|
timeCtr += deltaTime;
|
||
|
if (timeCtr >= seedUpdateRate)
|
||
|
{
|
||
|
++seedCtr;
|
||
|
timeCtr = 0.0;
|
||
|
}
|
||
|
return seedCtr;
|
||
|
}
|
||
|
|
||
|
void LensRenderModule::Init(const json& initData)
|
||
|
{
|
||
|
// Fetch needed resource
|
||
|
m_pColorSrc = GetFramework()->GetColorTargetForCallback(GetName());
|
||
|
|
||
|
switch (m_pColorSrc->GetFormat())
|
||
|
{
|
||
|
case ResourceFormat::RGBA16_FLOAT:
|
||
|
m_InitializationParameters.outputFormat = FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT;
|
||
|
break;
|
||
|
// For all other instances, just use floating point 32-bit format
|
||
|
default:
|
||
|
m_InitializationParameters.outputFormat = FFX_SURFACE_FORMAT_R11G11B10_FLOAT;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Create lens intermediate texture
|
||
|
TextureDesc desc = m_pColorSrc->GetDesc();
|
||
|
const ResolutionInfo& resInfo = GetFramework()->GetResolutionInfo();
|
||
|
desc.Width = resInfo.RenderWidth;
|
||
|
desc.Height = resInfo.RenderHeight;
|
||
|
desc.Name = L"Lens_Intermediate_Color";
|
||
|
m_pColorIntermediate = GetDynamicResourcePool()->CreateRenderTexture(
|
||
|
&desc, [](TextureDesc& desc, uint32_t displayWidth, uint32_t displayHeight, uint32_t renderingWidth, uint32_t renderingHeight) {
|
||
|
desc.Width = renderingWidth;
|
||
|
desc.Height = renderingHeight;
|
||
|
});
|
||
|
|
||
|
// Register UI
|
||
|
UISection* uiSection = GetUIManager()->RegisterUIElements("Lens effects", UISectionType::Sample);
|
||
|
|
||
|
// Add math combo
|
||
|
std::vector<const char*> comboOptions(s_FloatingPointMathOptions, s_FloatingPointMathOptions + _countof(s_FloatingPointMathOptions));
|
||
|
uiSection->RegisterUIElement<UICombo>(
|
||
|
"Lens Math",
|
||
|
(int32_t&)m_LensMath,
|
||
|
std::move(comboOptions),
|
||
|
[this](int32_t cur, int32_t old) {
|
||
|
if (m_ContextCreated)
|
||
|
{
|
||
|
// Refresh
|
||
|
UpdateLensContext(false);
|
||
|
UpdateLensContext(true);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Sliders for lens artistic constants
|
||
|
m_grainScale = 0.01f;
|
||
|
uiSection->RegisterUIElement<UISlider<float>>("Grain scale", (float&)m_grainScale, 0.01f, 20.0f);
|
||
|
|
||
|
m_grainAmount = 0.7f;
|
||
|
uiSection->RegisterUIElement<UISlider<float>>("Grain amount", (float&)m_grainAmount, 0.0f, 20.0f);
|
||
|
|
||
|
m_chromAb = 1.65f;
|
||
|
uiSection->RegisterUIElement<UISlider<float>>("Chromatic aberration intensity", (float&)m_chromAb, 0.0f, 20.0f);
|
||
|
|
||
|
m_vignette = 0.6f;
|
||
|
uiSection->RegisterUIElement<UISlider<float>>("Vignette intensity", (float&)m_vignette, 0.0f, 2.0f);
|
||
|
|
||
|
InitFfxContext();
|
||
|
|
||
|
GetFramework()->ConfigureRuntimeShaderRecompiler(
|
||
|
[this](void) { DestroyFfxContext(); }, [this](void) { InitFfxContext(); });
|
||
|
|
||
|
// We are now ready for use
|
||
|
SetModuleReady(true);
|
||
|
}
|
||
|
|
||
|
void LensRenderModule::InitFfxContext()
|
||
|
{
|
||
|
const size_t scratchBufferSize = SDKWrapper::ffxGetScratchMemorySize(FFX_LENS_CONTEXT_COUNT);
|
||
|
void* scratchBuffer = calloc(scratchBufferSize, 1u);
|
||
|
FfxErrorCode errorCode =
|
||
|
SDKWrapper::ffxGetInterface(&m_InitializationParameters.backendInterface, GetDevice(), scratchBuffer, scratchBufferSize, FFX_LENS_CONTEXT_COUNT);
|
||
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
||
|
CauldronAssert(ASSERT_CRITICAL, m_InitializationParameters.backendInterface.fpGetSDKVersion(&m_InitializationParameters.backendInterface) == FFX_SDK_MAKE_VERSION(1, 1, 2),
|
||
|
L"FidelityFX Lens 1.1 sample requires linking with a 1.1.2 version SDK backend");
|
||
|
CauldronAssert(ASSERT_CRITICAL, ffxLensGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 1, 0),
|
||
|
L"FidelityFX Lens 1.1 sample requires linking with a 1.1 version FidelityFX Lens library");
|
||
|
|
||
|
m_InitializationParameters.backendInterface.fpRegisterConstantBufferAllocator(&m_InitializationParameters.backendInterface, SDKWrapper::ffxAllocateConstantBuffer);
|
||
|
|
||
|
// Init Lens
|
||
|
UpdateLensContext(true);
|
||
|
}
|
||
|
|
||
|
LensRenderModule::~LensRenderModule()
|
||
|
{
|
||
|
// Flush anything out of the pipes before destroying the context
|
||
|
GetDevice()->FlushAllCommandQueues();
|
||
|
|
||
|
DestroyFfxContext();
|
||
|
}
|
||
|
|
||
|
void LensRenderModule::DestroyFfxContext()
|
||
|
{
|
||
|
UpdateLensContext(false);
|
||
|
|
||
|
// Destroy the FidelityFX interface memory
|
||
|
if (m_InitializationParameters.backendInterface.scratchBuffer != nullptr)
|
||
|
{
|
||
|
free(m_InitializationParameters.backendInterface.scratchBuffer);
|
||
|
m_InitializationParameters.backendInterface.scratchBuffer = nullptr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void LensRenderModule::UpdateLensContext(bool enabled)
|
||
|
{
|
||
|
if (!enabled)
|
||
|
{
|
||
|
// Flush anything out of the pipes before destroying the context
|
||
|
GetDevice()->FlushAllCommandQueues();
|
||
|
|
||
|
ffxLensContextDestroy(&m_LensContext);
|
||
|
m_ContextCreated = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Setup all the parameters for this Lens run
|
||
|
m_InitializationParameters.flags |= m_LensMath == FFX_LENS_FLOAT_PRECISION_16BIT ? FFX_LENS_MATH_PACKED : FFX_LENS_MATH_NONPACKED;
|
||
|
m_InitializationParameters.floatPrecision = GetFloatPrecision(m_LensMath);
|
||
|
|
||
|
ffxLensContextCreate(&m_LensContext, &m_InitializationParameters);
|
||
|
m_ContextCreated = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void LensRenderModule::Execute(double deltaTime, CommandList* pCmdList)
|
||
|
{
|
||
|
GPUScopedProfileCapture sampleMarker(pCmdList, L"Lens RM");
|
||
|
|
||
|
const ResolutionInfo& resInfo = GetFramework()->GetResolutionInfo();
|
||
|
|
||
|
FfxLensDispatchDescription dispatchParameters = {};
|
||
|
dispatchParameters.commandList = SDKWrapper::ffxGetCommandList(pCmdList);
|
||
|
dispatchParameters.renderSize = {resInfo.RenderWidth, resInfo.RenderHeight};
|
||
|
dispatchParameters.grainScale = m_grainScale;
|
||
|
dispatchParameters.grainAmount = m_grainAmount;
|
||
|
dispatchParameters.grainSeed = CalcGrainSeed(deltaTime, m_seedUpdateRate);
|
||
|
dispatchParameters.chromAb = m_chromAb;
|
||
|
dispatchParameters.vignette = m_vignette;
|
||
|
|
||
|
// Copy main color to intermediate buffer, then run lens on the intermediate, writing back into the main color buffer
|
||
|
std::vector<Barrier> barriers;
|
||
|
barriers.push_back(
|
||
|
Barrier::Transition(m_pColorSrc->GetResource(),
|
||
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource,
|
||
|
ResourceState::CopySource));
|
||
|
barriers.push_back(Barrier::Transition(m_pColorIntermediate->GetResource(),
|
||
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource,
|
||
|
ResourceState::CopyDest));
|
||
|
ResourceBarrier(pCmdList, static_cast<uint32_t>(barriers.size()), barriers.data());
|
||
|
|
||
|
TextureCopyDesc desc(m_pColorSrc->GetResource(), m_pColorIntermediate->GetResource());
|
||
|
CopyTextureRegion(pCmdList, &desc);
|
||
|
|
||
|
barriers[0] = Barrier::Transition(m_pColorIntermediate->GetResource(),
|
||
|
ResourceState::CopyDest,
|
||
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource);
|
||
|
barriers[1] = Barrier::Transition(m_pColorSrc->GetResource(),
|
||
|
ResourceState::CopySource,
|
||
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource);
|
||
|
ResourceBarrier(pCmdList, static_cast<uint32_t>(barriers.size()), barriers.data());
|
||
|
|
||
|
// All cauldron resources come into a render module in a generic read state (ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource)
|
||
|
dispatchParameters.resource = SDKWrapper::ffxGetResource(m_pColorIntermediate->GetResource(), L"Lens_Intermediate_Color", FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ);
|
||
|
dispatchParameters.resourceOutput = SDKWrapper::ffxGetResource(m_pColorSrc->GetResource(), L"Lens_Output", FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ);
|
||
|
|
||
|
FfxErrorCode errorCode = ffxLensContextDispatch(&m_LensContext, &dispatchParameters);
|
||
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
||
|
|
||
|
// FidelityFX contexts modify the set resource view heaps, so set the cauldron one back
|
||
|
SetAllResourceViewHeaps(pCmdList);
|
||
|
}
|
||
|
|
||
|
void LensRenderModule::OnResize(const ResolutionInfo& resInfo)
|
||
|
{
|
||
|
if (!ModuleEnabled())
|
||
|
return;
|
||
|
|
||
|
// Refresh
|
||
|
UpdateLensContext(false);
|
||
|
UpdateLensContext(true);
|
||
|
}
|