588 lines
23 KiB
C++
588 lines
23 KiB
C++
// This file is part of the FidelityFX Super Resolution 3.1 Unreal Engine Plugin.
|
|
//
|
|
// Copyright (c) 2023-2025 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
// 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 "FFXFrameInterpolationCustomPresent.h"
|
|
#include "RenderTargetPool.h"
|
|
#include "FFXFSR3Settings.h"
|
|
#include "GlobalShader.h"
|
|
#include "ShaderCompilerCore.h"
|
|
#include "PipelineStateCache.h"
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
#include "ShaderCompilerCore.h"
|
|
#else
|
|
#include "ShaderParameterUtils.h"
|
|
#endif
|
|
|
|
#if UE_VERSION_AT_LEAST(5, 2, 0)
|
|
#include "DataDrivenShaderPlatformInfo.h"
|
|
#else
|
|
#include "RHIDefinitions.h"
|
|
#endif
|
|
|
|
#if UE_VERSION_OLDER_THAN(5, 0, 0)
|
|
typedef FIntPoint FUintVector2;
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------------------------------
|
|
// Unreal shader to copy additional UI that only renders on the first invocation of Slate such as debug UI.
|
|
//------------------------------------------------------------------------------------------------------
|
|
class FFXFIAdditionalUICS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FFXFIAdditionalUICS, Global);
|
|
public:
|
|
static const int ThreadgroupSizeX = 8;
|
|
static const int ThreadgroupSizeY = 8;
|
|
static const int ThreadgroupSizeZ = 1;
|
|
|
|
FFXFIAdditionalUICS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FGlobalShader(Initializer)
|
|
{
|
|
FirstFrame.Bind(Initializer.ParameterMap, TEXT("FirstFrame"));
|
|
FirstFrameWithUI.Bind(Initializer.ParameterMap, TEXT("FirstFrameWithUI"));
|
|
SecondFrame.Bind(Initializer.ParameterMap, TEXT("SecondFrame"));
|
|
SecondFrameWithUI.Bind(Initializer.ParameterMap, TEXT("SecondFrameWithUI"));
|
|
ViewSize.Bind(Initializer.ParameterMap, TEXT("ViewSize"));
|
|
ViewMin.Bind(Initializer.ParameterMap, TEXT("ViewMin"));
|
|
}
|
|
FFXFIAdditionalUICS() {}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
OutEnvironment.SetDefine(TEXT("UNREAL_VERSION"), 5);
|
|
#else
|
|
OutEnvironment.SetDefine(TEXT("UNREAL_VERSION"), 4);
|
|
#endif
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEX"), ThreadgroupSizeX);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEY"), ThreadgroupSizeY);
|
|
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZEZ"), ThreadgroupSizeZ);
|
|
OutEnvironment.SetDefine(TEXT("COMPUTE_SHADER"), 1);
|
|
OutEnvironment.SetDefine(TEXT("UNREAL_ENGINE_MAJOR_VERSION"), ENGINE_MAJOR_VERSION);
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, FUintVector2 InViewSize, FUintVector2 InViewMin, FRHITexture* InFirstFrame, FRHITexture* InFirstFrameWithUI, FRHITexture* InSecondFrame, FRHIUnorderedAccessView* InSecondFrameWithUI)
|
|
{
|
|
#if UE_VERSION_AT_LEAST(5, 3, 0)
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
SetShaderValue(BatchedParameters, ViewSize, InViewSize, 0);
|
|
SetShaderValue(BatchedParameters, ViewMin, InViewMin, 0);
|
|
SetTextureParameter(BatchedParameters, FirstFrame, InFirstFrame);
|
|
SetTextureParameter(BatchedParameters, FirstFrameWithUI, InFirstFrameWithUI);
|
|
SetTextureParameter(BatchedParameters, SecondFrame, InSecondFrame);
|
|
SetUAVParameter(BatchedParameters, SecondFrameWithUI, InSecondFrameWithUI);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundComputeShader(), BatchedParameters);
|
|
#else
|
|
SetShaderValue(RHICmdList, RHICmdList.GetBoundComputeShader(), ViewSize, InViewSize);
|
|
SetShaderValue(RHICmdList, RHICmdList.GetBoundComputeShader(), ViewMin, InViewMin);
|
|
SetTextureParameter(RHICmdList, RHICmdList.GetBoundComputeShader(), FirstFrame, InFirstFrame);
|
|
SetTextureParameter(RHICmdList, RHICmdList.GetBoundComputeShader(), FirstFrameWithUI, InFirstFrameWithUI);
|
|
SetTextureParameter(RHICmdList, RHICmdList.GetBoundComputeShader(), SecondFrame, InSecondFrame);
|
|
SetUAVParameter(RHICmdList, RHICmdList.GetBoundComputeShader(), SecondFrameWithUI, InSecondFrameWithUI);
|
|
#endif
|
|
}
|
|
|
|
static const TCHAR* GetSourceFilename()
|
|
{
|
|
return TEXT("/Plugin/FSR3/Private/PostProcessFFX_FIAdditionalUI.usf");
|
|
}
|
|
|
|
static const TCHAR* GetFunctionName()
|
|
{
|
|
return TEXT("MainCS");
|
|
}
|
|
|
|
private:
|
|
LAYOUT_FIELD(FShaderResourceParameter, FirstFrame);
|
|
LAYOUT_FIELD(FShaderResourceParameter, FirstFrameWithUI);
|
|
LAYOUT_FIELD(FShaderResourceParameter, SecondFrame);
|
|
LAYOUT_FIELD(FShaderResourceParameter, SecondFrameWithUI);
|
|
LAYOUT_FIELD(FShaderParameter, ViewSize);
|
|
LAYOUT_FIELD(FShaderParameter, ViewMin);
|
|
};
|
|
IMPLEMENT_SHADER_TYPE(, FFXFIAdditionalUICS, TEXT("/Plugin/FSR3/Private/PostProcessFFX_FIAdditionalUI.usf"), TEXT("MainCS"), SF_Compute);
|
|
|
|
//------------------------------------------------------------------------------------------------------
|
|
// Implementation for FFXFrameInterpolationResources
|
|
//------------------------------------------------------------------------------------------------------
|
|
FFXFrameInterpolationResources::FFXFrameInterpolationResources(IFFXSharedBackend* InBackend, uint32 InUniqueID)
|
|
: FRHIResource(RRT_None)
|
|
, UniqueID(InUniqueID)
|
|
, Context(nullptr)
|
|
, Backend(InBackend)
|
|
, bDebugView(false)
|
|
{
|
|
FMemory::Memzero(Desc);
|
|
}
|
|
|
|
FFXFrameInterpolationResources::~FFXFrameInterpolationResources()
|
|
{
|
|
Backend->ffxDestroyContext(&Context);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------
|
|
// Implementation for FFXFrameInterpolationCustomPresent
|
|
//------------------------------------------------------------------------------------------------------
|
|
FFXFIResourceRef FFXFrameInterpolationCustomPresent::UpdateContexts(FRDGBuilder& GraphBuilder, uint32 UniqueID, ffxDispatchDescFrameGenerationPrepare const& FsrDesc, ffxCreateContextDescFrameGeneration const& FgDesc)
|
|
{
|
|
bool bResourcesValid = false;
|
|
FFXFIResourceRef Resource;
|
|
|
|
if (!bResized)
|
|
{
|
|
for (auto& Existing : OldResources)
|
|
{
|
|
bResourcesValid = Existing->UniqueID == UniqueID;
|
|
if (bResourcesValid)
|
|
{
|
|
Resource = Existing;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bResourcesValid)
|
|
{
|
|
bResourcesValid &= Resource->Desc.displaySize.width == FgDesc.displaySize.width;
|
|
bResourcesValid &= Resource->Desc.displaySize.height == FgDesc.displaySize.height;
|
|
bResourcesValid &= Resource->Desc.maxRenderSize.width == FgDesc.maxRenderSize.width;
|
|
bResourcesValid &= Resource->Desc.maxRenderSize.height == FgDesc.maxRenderSize.height;
|
|
bResourcesValid &= Resource->Desc.backBufferFormat == FgDesc.backBufferFormat;
|
|
bResourcesValid &= Resource->Desc.flags == FgDesc.flags;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bResized = false;
|
|
}
|
|
|
|
if (!bResourcesValid)
|
|
{
|
|
Resource = new FFXFrameInterpolationResources(Backend, UniqueID);
|
|
Resource->Desc = FgDesc;
|
|
|
|
auto Code = Backend->ffxCreateContext(&Resource->Context, &Resource->Desc.header);
|
|
if (Code != FFX_API_RETURN_OK)
|
|
{
|
|
Resource.SafeRelease();
|
|
}
|
|
}
|
|
CurrentResource = Resource;
|
|
if (CurrentResource.IsValid())
|
|
{
|
|
Resources.Add(CurrentResource);
|
|
}
|
|
check(CurrentResource.IsValid() && Resources.Num() > 0);
|
|
return Resource;
|
|
}
|
|
|
|
FFXFrameInterpolationCustomPresent::FFXFrameInterpolationCustomPresent()
|
|
: Backend(nullptr)
|
|
, Viewport(nullptr)
|
|
, RHIViewport(nullptr)
|
|
, Status(FFXFrameInterpolationCustomPresentStatus::PresentRT)
|
|
, Mode(EFFXFrameInterpolationPresentModeRHI)
|
|
, Api(EFFXBackendAPI::Unknown)
|
|
, bNeedsNativePresentRT(false)
|
|
, bPresentRHI(false)
|
|
, bHasValidInterpolatedRT(false)
|
|
, bEnabled(false)
|
|
, bResized(false)
|
|
, bUseFFXSwapchain(false)
|
|
, bHasInterpolatedRT(false)
|
|
, bHasInterpolatedRHI(false)
|
|
{
|
|
FMemory::Memzero(Desc);
|
|
}
|
|
|
|
FFXFrameInterpolationCustomPresent::~FFXFrameInterpolationCustomPresent()
|
|
{
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::InitViewport(FViewport* InViewport, FViewportRHIRef ViewportRHI)
|
|
{
|
|
Viewport = InViewport;
|
|
RHIViewport = ViewportRHI;
|
|
RHIViewport->SetCustomPresent(this);
|
|
}
|
|
|
|
bool FFXFrameInterpolationCustomPresent::InitSwapChain(IFFXSharedBackend* InBackend, uint32_t Flags, FIntPoint RenderSize, FIntPoint DisplaySize, FfxSwapchain RawSwapChain, FfxCommandQueue Queue, FfxApiSurfaceFormat Format, EFFXBackendAPI InApi)
|
|
{
|
|
Api = InApi;
|
|
|
|
FfxErrorCode Result = FFX_OK;
|
|
if (Backend != InBackend || Desc.flags != Flags || Desc.maxRenderSize.width != RenderSize.X || Desc.maxRenderSize.height != RenderSize.Y || Desc.displaySize.width != DisplaySize.X || Desc.displaySize.height != DisplaySize.Y || Format != Desc.backBufferFormat)
|
|
{
|
|
Desc.flags = Flags;
|
|
Desc.maxRenderSize.width = RenderSize.X;
|
|
Desc.maxRenderSize.height = RenderSize.Y;
|
|
Desc.displaySize.width = DisplaySize.X;
|
|
Desc.displaySize.height = DisplaySize.Y;
|
|
Desc.backBufferFormat = Format;
|
|
|
|
Backend = InBackend;
|
|
}
|
|
|
|
return (Result == FFX_OK);
|
|
}
|
|
|
|
// Called when viewport is resized.
|
|
void FFXFrameInterpolationCustomPresent::OnBackBufferResize()
|
|
{
|
|
bResized = true;
|
|
|
|
ENQUEUE_RENDER_COMMAND(FFXFrameInterpolationCustomPresentOnBackBufferResize)(
|
|
[this](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
RHICmdList.EnqueueLambda([this](FRHICommandListImmediate& cmd) mutable
|
|
{
|
|
ffxConfigureDescFrameGeneration ConfigDesc;
|
|
FMemory::Memzero(ConfigDesc);
|
|
ConfigDesc.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION;
|
|
ConfigDesc.swapChain = Backend->GetSwapchain(RHIViewport->GetNativeSwapChain());
|
|
ConfigDesc.frameGenerationEnabled = false;
|
|
ConfigDesc.allowAsyncWorkloads = false;
|
|
|
|
Backend->UpdateSwapChain(GetContext(), ConfigDesc);
|
|
});
|
|
});
|
|
|
|
// Flush the outstanding GPU work and wait for it to complete.
|
|
FlushRenderingCommands();
|
|
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
|
FRHICommandListExecutor::CheckNoOutstandingCmdLists();
|
|
#endif
|
|
}
|
|
|
|
// Called from render thread to see if a native present will be requested for this frame.
|
|
// @return true if native Present will be requested for this frame; false otherwise. Must
|
|
// match value subsequently returned by Present for this frame.
|
|
bool FFXFrameInterpolationCustomPresent::NeedsNativePresent()
|
|
{
|
|
if (Status == FFXFrameInterpolationCustomPresentStatus::PresentRT && (!bUseFFXSwapchain || bNeedsNativePresentRT))
|
|
{
|
|
if (!bHasInterpolatedRT)
|
|
{
|
|
SetEnabled(false);
|
|
}
|
|
bHasInterpolatedRT = false;
|
|
}
|
|
|
|
return bUseFFXSwapchain ? bNeedsNativePresentRT : true;
|
|
}
|
|
// In come cases we want to use custom present but still let the native environment handle
|
|
// advancement of the backbuffer indices.
|
|
// @return true if backbuffer index should advance independently from CustomPresent.
|
|
bool FFXFrameInterpolationCustomPresent::NeedsAdvanceBackbuffer()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Called from RHI thread when the engine begins drawing to the viewport.
|
|
void FFXFrameInterpolationCustomPresent::BeginDrawing()
|
|
{
|
|
}
|
|
|
|
// Called from RHI thread to perform custom present.
|
|
// @param InOutSyncInterval - in out param, indicates if vsync is on (>0) or off (==0).
|
|
// @return true if native Present should be also be performed; false otherwise. If it returns
|
|
// true, then InOutSyncInterval could be modified to switch between VSync/NoVSync for the normal
|
|
// Present. Must match value previously returned by NeedsNativePresent for this frame.
|
|
bool FFXFrameInterpolationCustomPresent::Present(int32& InOutSyncInterval)
|
|
{
|
|
bool bDrawDebugView = false;
|
|
#if (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT || UE_BUILD_TEST)
|
|
bDrawDebugView = CVarFFXFIShowDebugView.GetValueOnAnyThread() != 0;
|
|
#endif
|
|
|
|
if (bPresentRHI)
|
|
{
|
|
if (!bHasInterpolatedRHI && GetContext())
|
|
{
|
|
ffxConfigureDescFrameGeneration ConfigDesc;
|
|
FMemory::Memzero(ConfigDesc);
|
|
ConfigDesc.header.type = FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION;
|
|
ConfigDesc.swapChain = GetBackend()->GetSwapchain(RHIViewport->GetNativeSwapChain());
|
|
ConfigDesc.frameGenerationEnabled = false;
|
|
ConfigDesc.allowAsyncWorkloads = false;
|
|
GetBackend()->UpdateSwapChain(GetContext(), ConfigDesc);
|
|
}
|
|
bHasInterpolatedRHI = false;
|
|
}
|
|
|
|
if (bUseFFXSwapchain && !bPresentRHI && !bDrawDebugView && Current.Interpolated.GetReference())
|
|
{
|
|
FfxSwapchain SwapChain = GetBackend()->GetSwapchain(RHIViewport->GetNativeSwapChain());
|
|
FfxApiResource OutputRes = GetBackend()->GetInterpolationOutput(SwapChain);
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
FfxApiResource Interpolated = GetBackend()->GetNativeResource(Current.Interpolated->GetRHI(), CVarFFXFICaptureDebugUI.GetValueOnAnyThread() ? FFX_API_RESOURCE_STATE_COMPUTE_READ : FFX_API_RESOURCE_STATE_COPY_DEST);
|
|
#else
|
|
FfxApiResource Interpolated = GetBackend()->GetNativeResource(Current.Interpolated->GetRHI(ERenderTargetTexture::Targetable), CVarFFXFICaptureDebugUI.GetValueOnAnyThread() ? FFX_API_RESOURCE_STATE_COMPUTE_READ : FFX_API_RESOURCE_STATE_COPY_DEST);
|
|
#endif
|
|
FfxCommandList CmdList = GetBackend()->GetInterpolationCommandList(SwapChain);
|
|
FIntPoint Size = FIntPoint(OutputRes.description.width, OutputRes.description.height);
|
|
if (CmdList)
|
|
{
|
|
GetBackend()->CopySubRect(CmdList, Interpolated, OutputRes, Size, FIntPoint(0, 0));
|
|
}
|
|
}
|
|
|
|
int32 PaceRHIFrames = CVarFSR3PaceRHIFrames.GetValueOnAnyThread();
|
|
if (!bUseFFXSwapchain && (Api == EFFXBackendAPI::Unreal) && (PaceRHIFrames != 0) && bPresentRHI && !bDrawDebugView && Current.Interpolated.GetReference())
|
|
{
|
|
InOutSyncInterval = 1;
|
|
}
|
|
|
|
return (!bUseFFXSwapchain || bDrawDebugView || bPresentRHI);
|
|
}
|
|
|
|
// Called from RHI thread after native Present has been called
|
|
void FFXFrameInterpolationCustomPresent::PostPresent()
|
|
{
|
|
}
|
|
|
|
// Called when rendering thread is acquired
|
|
void FFXFrameInterpolationCustomPresent::OnAcquireThreadOwnership()
|
|
{
|
|
}
|
|
|
|
// Called when rendering thread is released
|
|
void FFXFrameInterpolationCustomPresent::OnReleaseThreadOwnership()
|
|
{
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::CopyBackBufferRT(FTextureRHIRef InBackBuffer)
|
|
{
|
|
if (Enabled() && (Status == FFXFrameInterpolationCustomPresentStatus::InterpolateRT || Status == FFXFrameInterpolationCustomPresentStatus::PresentRT))
|
|
{
|
|
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
|
|
|
|
FRHICopyTextureInfo Info;
|
|
Info.Size.X = InBackBuffer->GetSizeX();
|
|
Info.Size.Y = InBackBuffer->GetSizeY();
|
|
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
ETextureCreateFlags DescFlags = TexCreate_UAV;
|
|
#else
|
|
ETextureCreateFlags DescFlags = TexCreate_None;
|
|
#endif
|
|
FPooledRenderTargetDesc RTDesc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(Info.Size.X, Info.Size.Y),
|
|
InBackBuffer->GetFormat(),
|
|
FClearValueBinding::Transparent,
|
|
DescFlags,
|
|
TexCreate_UAV|TexCreate_ShaderResource,
|
|
false,
|
|
1,
|
|
true,
|
|
true));
|
|
|
|
switch(Status)
|
|
{
|
|
case FFXFrameInterpolationCustomPresentStatus::InterpolateRT:
|
|
{
|
|
check(Mode == EFFXFrameInterpolationPresentModeRHI);
|
|
auto& Dest = Current.Interpolated;
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, RTDesc, Dest, TEXT("Interpolated"));
|
|
check(FIntPoint(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y) == Dest->GetDesc().Extent);
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(Dest->GetRHI(), ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
RHICmdList.CopyTexture(InBackBuffer, Dest->GetRHI(), Info);
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::Present),
|
|
FRHITransitionInfo(Dest->GetRHI(), ERHIAccess::Unknown, ERHIAccess::SRVCompute),
|
|
});
|
|
#else
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(Dest->GetRHI(ERenderTargetTexture::Targetable), ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
RHICmdList.CopyTexture(InBackBuffer, Dest->GetRHI(ERenderTargetTexture::Targetable), Info);
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::Present),
|
|
FRHITransitionInfo(Dest->GetRHI(ERenderTargetTexture::Targetable), ERHIAccess::Unknown, ERHIAccess::SRVCompute),
|
|
});
|
|
#endif
|
|
bHasValidInterpolatedRT = true;
|
|
break;
|
|
}
|
|
case FFXFrameInterpolationCustomPresentStatus::PresentRT:
|
|
{
|
|
|
|
|
|
#if UE_VERSION_AT_LEAST(5, 5, 0)
|
|
SCOPED_DRAW_EVENT(RHICmdList, FFXFrameInterpolationCustomPresent::CopyBackBufferRT PresentRT)
|
|
#else
|
|
RHICmdList.PushEvent(TEXT("FFXFrameInterpolationCustomPresent::CopyBackBufferRT PresentRT"), FColor::White);
|
|
#endif
|
|
|
|
auto& SecondFrameUI = Current.RealFrame;
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, RTDesc, SecondFrameUI, TEXT("RealFrame"));
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(SecondFrameUI->GetRHI(), ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
check(FIntPoint(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y) == SecondFrameUI->GetDesc().Extent);
|
|
RHICmdList.CopyTexture(InBackBuffer, SecondFrameUI->GetRHI(), Info);
|
|
#else
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(SecondFrameUI->GetRHI(ERenderTargetTexture::Targetable), ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
check(FIntPoint(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y) == SecondFrameUI->GetDesc().Extent);
|
|
RHICmdList.CopyTexture(InBackBuffer, SecondFrameUI->GetRHI(ERenderTargetTexture::Targetable), Info);
|
|
#endif
|
|
if (CVarFFXFICaptureDebugUI.GetValueOnAnyThread() && bHasValidInterpolatedRT && (Mode == EFFXFrameInterpolationPresentModeRHI))
|
|
{
|
|
auto& FirstFrame = InterpolatedNoUI;
|
|
auto& SecondFrame = RealFrameNoUI;
|
|
auto& FirstFrameUI = Current.Interpolated;
|
|
#if UE_VERSION_AT_LEAST(5, 3, 0)
|
|
auto RWSecondFrameUI = FRHICommandListExecutor::GetImmediateCommandList().CreateUnorderedAccessView(SecondFrameUI->GetRHI());
|
|
#elif UE_VERSION_AT_LEAST(5, 0, 0)
|
|
auto RWSecondFrameUI = RHICreateUnorderedAccessView(SecondFrameUI->GetRHI());
|
|
#else
|
|
auto RWSecondFrameUI = RHICreateUnorderedAccessView(SecondFrameUI->GetRHI(ERenderTargetTexture::Targetable));
|
|
#endif
|
|
|
|
TShaderRef<FFXFIAdditionalUICS> ComputeShader = TShaderMapRef<FFXFIAdditionalUICS>(GetGlobalShaderMap(GMaxRHIFeatureLevel));
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(RWSecondFrameUI, ERHIAccess::Unknown, ERHIAccess::UAVCompute),
|
|
});
|
|
|
|
FIntPoint Extent(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y);
|
|
SetComputePipelineState(RHICmdList, ComputeShader.GetComputeShader());
|
|
#if UE_VERSION_AT_LEAST(5, 0, 0)
|
|
ComputeShader->SetParameters(RHICmdList, FUintVector2(Extent.X, Extent.Y), FUintVector2(0, 0), FirstFrame->GetRHI(), FirstFrameUI->GetRHI(), SecondFrame->GetRHI(), RWSecondFrameUI);
|
|
|
|
RHICmdList.DispatchComputeShader(FMath::DivideAndRoundUp(Extent.X, FFXFIAdditionalUICS::ThreadgroupSizeX), FMath::DivideAndRoundUp(Extent.Y, FFXFIAdditionalUICS::ThreadgroupSizeY), 1);
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(SecondFrameUI->GetRHI(), ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
check(SecondFrameUI->GetDesc().Extent == FIntPoint(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y));
|
|
|
|
RHICmdList.CopyTexture(SecondFrameUI->GetRHI(), InBackBuffer, Info);
|
|
#else
|
|
ComputeShader->SetParameters(RHICmdList, FIntPoint(Extent.X, Extent.Y), FIntPoint(0, 0), FirstFrame->GetRHI(ERenderTargetTexture::Targetable), FirstFrameUI->GetRHI(ERenderTargetTexture::Targetable), SecondFrame->GetRHI(ERenderTargetTexture::Targetable), RWSecondFrameUI);
|
|
|
|
RHICmdList.DispatchComputeShader(FMath::DivideAndRoundUp(Extent.X, FFXFIAdditionalUICS::ThreadgroupSizeX), FMath::DivideAndRoundUp(Extent.Y, FFXFIAdditionalUICS::ThreadgroupSizeY), 1);
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(SecondFrameUI->GetRHI(ERenderTargetTexture::Targetable), ERHIAccess::Unknown, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::CopyDest)
|
|
});
|
|
|
|
check(SecondFrameUI->GetDesc().Extent == FIntPoint(InBackBuffer->GetSizeXYZ().X, InBackBuffer->GetSizeXYZ().Y));
|
|
|
|
RHICmdList.CopyTexture(SecondFrameUI->GetRHI(ERenderTargetTexture::Targetable), InBackBuffer, Info);
|
|
#endif
|
|
}
|
|
|
|
RHICmdList.Transition({
|
|
FRHITransitionInfo(InBackBuffer, ERHIAccess::Unknown, ERHIAccess::Present)
|
|
});
|
|
|
|
bHasValidInterpolatedRT = false;
|
|
|
|
#if UE_VERSION_OLDER_THAN(5, 5, 0)
|
|
RHICmdList.PopEvent();
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::SetMode(EFFXFrameInterpolationPresentMode InMode)
|
|
{
|
|
Mode = InMode;
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::SetEnabled(bool const bInEnabled)
|
|
{
|
|
bEnabled = bInEnabled;
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::SetCustomPresentStatus(FFXFrameInterpolationCustomPresentStatus Flag)
|
|
{
|
|
switch (Flag)
|
|
{
|
|
case FFXFrameInterpolationCustomPresentStatus::InterpolateRT:
|
|
{
|
|
bHasInterpolatedRT = true;
|
|
if (GetMode() != EFFXFrameInterpolationPresentModeNative)
|
|
{
|
|
Status = Flag;
|
|
bNeedsNativePresentRT = false;
|
|
break;
|
|
}
|
|
// Else is deliberately falling through
|
|
}
|
|
case FFXFrameInterpolationCustomPresentStatus::PresentRT:
|
|
{
|
|
Status = FFXFrameInterpolationCustomPresentStatus::PresentRT;
|
|
bNeedsNativePresentRT = true;
|
|
break;
|
|
}
|
|
case FFXFrameInterpolationCustomPresentStatus::InterpolateRHI:
|
|
{
|
|
bHasInterpolatedRHI = true;
|
|
if (GetMode() != EFFXFrameInterpolationPresentModeNative)
|
|
{
|
|
bPresentRHI = false;
|
|
break;
|
|
}
|
|
// Else is deliberately falling through
|
|
}
|
|
case FFXFrameInterpolationCustomPresentStatus::PresentRHI:
|
|
{
|
|
bPresentRHI = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FFXFrameInterpolationCustomPresent::SetUseFFXSwapchain(bool const bToggle)
|
|
{
|
|
bUseFFXSwapchain = bToggle;
|
|
}
|