Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for lens distortion offsets in Frame Interpolation #86

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ffx-api/include/ffx_api/ffx_framegeneration.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ struct ffxDispatchDescFrameGeneration
void* commandList; ///< The command list on which to register render commands.
struct FfxApiResource presentColor; ///< The current presentation color, this will be used as source data.
struct FfxApiResource outputs[4]; ///< Destination targets (1 for each frame in numGeneratedFrames).
struct FfxApiResource distortionField; ///< The distortion field data.
uint32_t numGeneratedFrames; ///< The number of frames to generate from the passed in color target.
bool reset; ///< A boolean value which when set to true, indicates the camera has moved discontinuously.
uint32_t backbufferTransferFunction; ///< The transfer function use to convert frame generation source color data to linear RGB. One of the values from FfxApiBackbufferTransferFunction.
Expand Down
1 change: 1 addition & 0 deletions ffx-api/src/ffx_provider_framegeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ ffxReturnCode_t ffxProvider_FrameGeneration::Dispatch(ffxContext* context, const
fiDispatchDesc.renderSize.width = prepDesc->renderSize.width;
fiDispatchDesc.renderSize.height = prepDesc->renderSize.height;
fiDispatchDesc.output = Convert(desc->outputs[0]);
fiDispatchDesc.distortionField = Convert(desc->distortionField);
fiDispatchDesc.opticalFlowVector = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_VECTOR]);
fiDispatchDesc.opticalFlowSceneChangeDetection = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_SCD_OUTPUT]);
fiDispatchDesc.opticalFlowBlockSize = 8;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 "tonemappercommon.h"
#include "lensdistortion.h"

//--------------------------------------------------------------------------------------
// Texture definitions
//--------------------------------------------------------------------------------------
RWTexture2D<float4> OutputTexture : register(u0);

bool IsInsideLetterbox(int2 pixel)
{
if (pixel.x > LetterboxRectBase.x && pixel.y > LetterboxRectBase.y &&
pixel.x < LetterboxRectBase.x + LetterboxRectSize.x &&
pixel.y <= LetterboxRectBase.y + LetterboxRectSize.y)
return true;

return false;
}

//--------------------------------------------------------------------------------------
// Main function
//--------------------------------------------------------------------------------------
[numthreads(NUM_THREAD_X, NUM_THREAD_Y, 1)]
void MainCS(uint3 dtID : SV_DispatchThreadID)
{
const uint2 pixel = dtID.xy;

float4 distortionField = float4(0.0f, 0.0f, 0.0f, 0.0f);
if (IsInsideLetterbox(pixel))
{
float2 uv = (pixel + 0.5f) / LetterboxRectSize;
distortionField = GenerateDistortionField(uv);
}
OutputTexture[pixel] = distortionField;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 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.

#ifndef LENSDISTORTION_HLSL
#define LENSDISTORTION_HLSL

#include "tonemappercommon.h"

float2 BarrelDistortion(in float2 Uv)
{
float2 remappedUv = (Uv * 2.0f) - 1.0f;
float r2 = remappedUv.x * remappedUv.x + remappedUv.y * remappedUv.y;
float2 outUv = remappedUv / (1.0f + LensDistortionStrength * r2);
return (outUv + 1.0f) / 2.0f;
}

float2 InverseBarrelDistortion(in float2 Uv)
{
float2 remappedUv = (Uv * 2.0f) - 1.0f;
float ru2 = remappedUv.x * remappedUv.x + remappedUv.y * remappedUv.y;
float num = sqrt(1.0f - 4.0f * LensDistortionStrength * ru2) - 1.0f;
float denom = 2.0f * LensDistortionStrength * sqrt(ru2);
float rd = -num / denom;
float2 outUV = remappedUv * (rd / sqrt(ru2));
return (outUV + 1.0f) / 2.0f;
}

float2 Zoom(in float2 Uv)
{
float2 translatedCoord = (Uv - 0.5f) * 2.0f;
translatedCoord *= (1.0f - saturate(LensDistortionZoom));
return (translatedCoord + 1.0f) / 2.0f;
}

float2 InverseZoom(in float2 Uv)
{
float2 translatedCoord = (Uv - 0.5f) * 2.0f;
translatedCoord /= (1.0f - saturate(LensDistortionZoom));
return (translatedCoord + 1.0f) / 2.0f;
}

float4 GenerateDistortionField(in float2 Uv)
{
float2 xy = Zoom(BarrelDistortion(Uv)) - Uv;
float2 zw = InverseBarrelDistortion(InverseZoom(Uv)) - Uv;
return float4(xy, zw);
}

float2 ApplyLensDistortion(in float2 Uv)
{
return Zoom(BarrelDistortion(Uv));
}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#ifndef TONEMAPPERCOMMON_H
#define TONEMAPPERCOMMON_H

#if __cplusplus
#pragma once
#include <shaders/shadercommon.h>
Expand All @@ -42,10 +45,17 @@ struct TonemapperCBData
mutable uint32_t ToneMapper = 0;
float DisplayMaxLuminance;
DisplayMode MonitorDisplayMode;

Mat4 ContentToMonitorRecMatrix;

int32_t LetterboxRectBase[2];
int32_t LetterboxRectSize[2];

uint32_t UseAutoExposure = 0;
uint32_t LensDistortionEnabled = 0;
float LensDistortionStrength = -0.2f;
float LensDistortionZoom = 0.4f;


};
#else
Expand All @@ -67,5 +77,10 @@ cbuffer TonemapperCBData : register(b0)
int2 LetterboxRectBase : packoffset(c5.x);
int2 LetterboxRectSize : packoffset(c5.z);
bool UseAutoExposure : packoffset(c6.x);
bool LensDistortionEnabled : packoffset(c6.y);
float LensDistortionStrength : packoffset(c6.z);
float LensDistortionZoom : packoffset(c6.w);
}
#endif // __cplusplus

#endif // TONEMAPPERCOMMON_H
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "tonemappers.hlsl"
#include "tonemappercommon.h"
#include "transferfunction.h"
#include "lensdistortion.h"

//--------------------------------------------------------------------------------------
// Texture definitions
Expand All @@ -48,7 +49,14 @@ void MainCS(uint3 dtID : SV_DispatchThreadID)
}
else
{
const int2 coordInLetterbox = dtID.xy - LetterboxRectBase;
int2 coordInLetterbox = dtID.xy - LetterboxRectBase;

if (LensDistortionEnabled)
{
const float2 uvInLetterbox = (coordInLetterbox + 0.5f) / LetterboxRectSize;
const float2 distortedUvInLetterbox = ApplyLensDistortion(uvInLetterbox);
coordInLetterbox = distortedUvInLetterbox * LetterboxRectSize;
}
const float4 texColor = InputTexture[coordInLetterbox];

const float2 autoExposure = AutomaticExposureValue[int2(0, 0)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ void ToneMappingRenderModule::Init(const json& InitData)
m_pRenderTargetOut = GetFramework()->GetRenderTexture(L"SwapChainProxy");
CauldronAssert(ASSERT_CRITICAL, m_pRenderTargetOut != nullptr, L"Couldn't find the render target for the tone mapper output");

m_pDistortionField = GetFramework()->GetRenderTexture(L"DistortionField");

TextureDesc desc = TextureDesc::Tex2D(L"AutomaticExposureSpdAtomicCounter", ResourceFormat::R32_UINT, 1, 1, 1, 1, ResourceFlags::AllowUnorderedAccess);
m_pAutomaticExposureSpdAtomicCounter = GetDynamicResourcePool()->CreateRenderTexture(&desc);

Expand Down Expand Up @@ -133,6 +135,31 @@ void ToneMappingRenderModule::Init(const json& InitData)
m_pAutoExposureSpdParameters->SetTextureUAV(m_pAutomaticExposureMips5, ViewDimension::Texture2D, 2);
m_pAutoExposureSpdParameters->SetTextureUAV(m_pAutomaticExposureValue, ViewDimension::Texture2D, 3);

{
// Init build distortion field pipeline
RootSignatureDesc buildDistortionFieldSignatureDesc;
buildDistortionFieldSignatureDesc.AddConstantBufferView(0, ShaderBindStage::Compute, 1);
buildDistortionFieldSignatureDesc.AddTextureUAVSet(0, ShaderBindStage::Compute, 1);
m_pBuildDistortionFieldRootSignature = RootSignature::CreateRootSignature(L"BuildDistortionFieldRenderPass_RootSignature", buildDistortionFieldSignatureDesc);

// Setup the pipeline object
PipelineDesc buildDistortionFieldPsoDesc;
buildDistortionFieldPsoDesc.SetRootSignature(m_pBuildDistortionFieldRootSignature);

// Setup the shaders to build on the pipeline object
shaderPath = L"builddistortionfield.hlsl";

DefineList buildDistortionFieldDefineList;
buildDistortionFieldDefineList.insert(std::make_pair(L"NUM_THREAD_X", std::to_wstring(g_NumThreadX)));
buildDistortionFieldDefineList.insert(std::make_pair(L"NUM_THREAD_Y", std::to_wstring(g_NumThreadY)));
buildDistortionFieldPsoDesc.AddShaderDesc(ShaderBuildDesc::Compute(shaderPath.c_str(), L"MainCS", ShaderModel::SM6_0, &buildDistortionFieldDefineList));

m_pBuildDistortionFieldPipelineObj = PipelineObject::CreatePipelineObject(L"BuildDistortionFieldRenderPass_PipelineObj", buildDistortionFieldPsoDesc);

m_pBuildDistortionFieldParameters = ParameterSet::CreateParameterSet(m_pBuildDistortionFieldRootSignature);
m_pBuildDistortionFieldParameters->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(TonemapperCBData), 0);
m_pBuildDistortionFieldParameters->SetTextureUAV(m_pDistortionField, ViewDimension::Texture2D, 0);
}
// Init tonemapper
// root signature
RootSignatureDesc tonemapperSignatureDesc;
Expand Down Expand Up @@ -182,6 +209,10 @@ void ToneMappingRenderModule::Init(const json& InitData)
}
);
uiSection->RegisterUIElement<UICheckBox>("AutoExposure", (bool&)m_TonemapperConstantData.UseAutoExposure);

uiSection->RegisterUIElement<UICheckBox>("Lens Distortion Enable", (bool&)m_TonemapperConstantData.LensDistortionEnabled);
uiSection->RegisterUIElement<UISlider<float>>("Lens Distortion Strength", m_TonemapperConstantData.LensDistortionStrength, -1.f, 1.f, m_TonemapperConstantData.LensDistortionEnabled, nullptr, true);
uiSection->RegisterUIElement<UISlider<float>>("Lens Distortion Zoom", m_TonemapperConstantData.LensDistortionZoom, 0.f, 1.f, m_TonemapperConstantData.LensDistortionEnabled, nullptr, true);
}

// We are now ready for use
Expand All @@ -194,6 +225,10 @@ ToneMappingRenderModule::~ToneMappingRenderModule()
delete m_pAutoExposureSpdPipelineObj;
delete m_pAutoExposureSpdParameters;

delete m_pBuildDistortionFieldRootSignature;
delete m_pBuildDistortionFieldPipelineObj;
delete m_pBuildDistortionFieldParameters;

delete m_pTonemapperRootSignature;
delete m_pTonemapperPipelineObj;
delete m_pTonemapperParameters;
Expand Down Expand Up @@ -238,7 +273,7 @@ void ToneMappingRenderModule::Execute(double deltaTime, CommandList* pCmdList)

Dispatch(pCmdList, m_DispatchThreadGroupCountXY[0], m_DispatchThreadGroupCountXY[1], 1);
}

{
GPUScopedProfileCapture tonemappingMarker(pCmdList, L"ToneMapping");

Expand Down Expand Up @@ -302,4 +337,33 @@ void ToneMappingRenderModule::Execute(double deltaTime, CommandList* pCmdList)
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource);
ResourceBarrier(pCmdList, 1, &barrier);
}

if (m_TonemapperConstantData.LensDistortionEnabled)
{
GPUScopedProfileCapture distortionFieldMarker(pCmdList, L"Build Distortion Field");

Barrier barrierToWrite = Barrier::Transition(m_pDistortionField->GetResource(),
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource,
ResourceState::UnorderedAccess);
ResourceBarrier(pCmdList, 1, &barrierToWrite);

// Allocate a dynamic constant buffer and set
BufferAddressInfo bufferInfo = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(TonemapperCBData), &m_TonemapperConstantData);
m_pBuildDistortionFieldParameters->UpdateRootConstantBuffer(&bufferInfo, 0);

// bind all the parameters
m_pBuildDistortionFieldParameters->Bind(pCmdList, m_pBuildDistortionFieldPipelineObj);

// Set pipeline and dispatch
SetPipelineState(pCmdList, m_pBuildDistortionFieldPipelineObj);

const uint32_t numGroupX = DivideRoundingUp(m_pDistortionField->GetDesc().Width, g_NumThreadX);
const uint32_t numGroupY = DivideRoundingUp(m_pDistortionField->GetDesc().Height, g_NumThreadY);
Dispatch(pCmdList, numGroupX, numGroupY, 1);

Barrier barrierToRead = Barrier::Transition(m_pDistortionField->GetResource(),
ResourceState::UnorderedAccess,
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource);
ResourceBarrier(pCmdList, 1, &barrierToRead);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,18 @@ class ToneMappingRenderModule : public cauldron::RenderModule
// Constant data
uint32_t m_DispatchThreadGroupCountXY[2];

AutoExposureSpdConstants m_AutoExposureSpdConstants;
TonemapperCBData m_TonemapperConstantData;
AutoExposureSpdConstants m_AutoExposureSpdConstants;
TonemapperCBData m_TonemapperConstantData;

// common
cauldron::RootSignature* m_pAutoExposureSpdRootSignature = nullptr;
cauldron::PipelineObject* m_pAutoExposureSpdPipelineObj = nullptr;
cauldron::ParameterSet* m_pAutoExposureSpdParameters = nullptr;

cauldron::RootSignature* m_pBuildDistortionFieldRootSignature = nullptr;
cauldron::PipelineObject* m_pBuildDistortionFieldPipelineObj = nullptr;
cauldron::ParameterSet* m_pBuildDistortionFieldParameters = nullptr;

cauldron::RootSignature* m_pTonemapperRootSignature = nullptr;
const cauldron::RasterView* m_pRasterView = nullptr;
cauldron::PipelineObject* m_pTonemapperPipelineObj = nullptr;
Expand All @@ -77,5 +81,6 @@ class ToneMappingRenderModule : public cauldron::RenderModule
cauldron::SamplerDesc m_LinearSamplerDesc;

const cauldron::Texture* m_pRenderTargetIn = nullptr;
const cauldron::Texture* m_pRenderTargetOut = nullptr;
const cauldron::Texture* m_pRenderTargetOut = nullptr;
const cauldron::Texture* m_pDistortionField = nullptr;
};
5 changes: 5 additions & 0 deletions samples/fsrapi/config/fsrapiconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"MotionVectorGeneration": "GBufferRenderModule",

"RenderResources": {
"DistortionField": {
"Format": "RGBA16_FLOAT",
"AllowUAV": true,
"RenderResolution": false
},
"ReactiveMask": {
"Format": "R8_UNORM",
"AllowUAV": true,
Expand Down
Loading