diff --git a/source/maindll/FFInterpolator.cpp b/source/maindll/FFInterpolator.cpp new file mode 100644 index 0000000..cf626dd --- /dev/null +++ b/source/maindll/FFInterpolator.cpp @@ -0,0 +1,153 @@ +#include "FFInterpolator.h" + +FFInterpolator::FFInterpolator(const FfxInterface& BackendInterface, uint32_t MaxRenderWidth, uint32_t MaxRenderHeight) + : m_BackendInterface(BackendInterface), + m_MaxRenderWidth(MaxRenderWidth), + m_MaxRenderHeight(MaxRenderHeight) +{ +} + +FFInterpolator::~FFInterpolator() +{ + if (m_ResourceCreationHackActive) + { + const uint32_t resourceId = FFX_FRAMEINTERPOLATION_RESOURCE_IDENTIFIER_PREVIOUS_INTERPOLATION_SOURCE; + auto context = reinterpret_cast(&m_Context); + + context->srvResources[resourceId] = m_OriginalPreviousInterpolationSource; + context->uavResources[resourceId] = m_OriginalPreviousInterpolationSource; + + context->contextDescription.backendInterface.fpDestroyResource( + &context->contextDescription.backendInterface, + m_HackPreviousInterpolationSource, + context->effectContextId); + } + + if (m_ContextCreated) + ffxFrameInterpolationContextDestroy(&m_Context); +} + +FfxErrorCode FFInterpolator::Dispatch(const FFInterpolatorDispatchParameters& Parameters) +{ + FFX_RETURN_ON_FAIL(InternalDeferredSetupContext(Parameters)); // Massive frame hitch on first call + + FfxFrameInterpolationDispatchDescription desc = {}; + + if (Parameters.DebugTearLines) + desc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_DRAW_DEBUG_TEAR_LINES; + + if (Parameters.DebugView) + desc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_DRAW_DEBUG_VIEW; + + desc.commandList = Parameters.CommandList; + desc.displaySize = Parameters.OutputSize; + desc.renderSize = Parameters.RenderSize; + + desc.currentBackBuffer = Parameters.InputColorBuffer; + desc.currentBackBuffer_HUDLess = Parameters.InputHUDLessColorBuffer; + desc.output = Parameters.OutputColorBuffer; + desc.dilatedDepth = Parameters.InputDilatedDepth; + desc.dilatedMotionVectors = Parameters.InputDilatedMotionVectors; + desc.reconstructPrevNearDepth = Parameters.InputReconstructedPreviousNearDepth; + + desc.interpolationRect = { 0, 0, static_cast(desc.displaySize.width), static_cast(desc.displaySize.height) }; + + desc.opticalFlowVector = Parameters.InputOpticalFlowVector; + desc.opticalFlowSceneChangeDetection = Parameters.InputOpticalFlowSceneChangeDetection; + desc.opticalFlowBufferSize = Parameters.OpticalFlowBufferSize; + desc.opticalFlowScale = Parameters.OpticalFlowScale; + desc.opticalFlowBlockSize = Parameters.OpticalFlowBlockSize; + + desc.cameraNear = Parameters.CameraNear; + desc.cameraFar = Parameters.CameraFar; + desc.cameraFovAngleVertical = Parameters.CameraFovAngleVertical; + desc.viewSpaceToMetersFactor = Parameters.ViewSpaceToMetersFactor; + + desc.frameTimeDelta = 1000.0f / 60.0f; // Unused + desc.reset = Parameters.Reset; + + desc.backBufferTransferFunction = Parameters.HDR ? FFX_BACKBUFFER_TRANSFER_FUNCTION_PQ : FFX_BACKBUFFER_TRANSFER_FUNCTION_SRGB; + desc.minMaxLuminance[0] = Parameters.MinMaxLuminance.x; + desc.minMaxLuminance[1] = Parameters.MinMaxLuminance.y; + + return ffxFrameInterpolationDispatch(&m_Context, &desc); +} + +FfxErrorCode FFInterpolator::InternalDeferredSetupContext(const FFInterpolatorDispatchParameters& Parameters) +{ + if (!m_ContextCreated) + { + FfxFrameInterpolationContextDescription desc = {}; + desc.backendInterface = m_BackendInterface; + + if (Parameters.HDR) + desc.flags |= FFX_FRAMEINTERPOLATION_ENABLE_HDR_COLOR_INPUT; + + if (Parameters.DepthInverted) + desc.flags |= FFX_FRAMEINTERPOLATION_ENABLE_DEPTH_INVERTED; + + desc.maxRenderSize = { m_MaxRenderWidth, m_MaxRenderHeight }; + desc.displaySize = desc.maxRenderSize; + + // If provided, pretend the input hudless color format is the back buffer format + desc.backBufferFormat = Parameters.InputColorBuffer.description.format; + + if (Parameters.InputHUDLessColorBuffer.resource) + desc.backBufferFormat = Parameters.InputHUDLessColorBuffer.description.format; + + FFX_RETURN_ON_FAIL(ffxFrameInterpolationContextCreate(&m_Context, &desc)); + + m_InitialBackBufferFormat = desc.backBufferFormat; + m_ContextCreated = true; + } + + // What FFX calls "backBufferFormat" is actually the format of the input color buffer. The input + // color buffer could be the back buffer, or it could be a HUD-less equivalent. Either way, code + // assumes they're identical formats and trips an assert if they're not. The assert is bogus since + // AMD's new implementation is format-agnostic. We can work around this limitation by swapping + // internal resource handles around. + auto& currentInputColor = Parameters.InputHUDLessColorBuffer.resource ? Parameters.InputHUDLessColorBuffer + : Parameters.InputColorBuffer; + + if (currentInputColor.description.format != m_InitialBackBufferFormat) + FFX_RETURN_ON_FAIL(InternalSwapResources(currentInputColor.description.format)); + + return FFX_OK; +} + +FfxErrorCode FFInterpolator::InternalSwapResources(FfxSurfaceFormat NewFormat) +{ + if (m_ResourceCreationHackActive) + return FFX_OK; + + const uint32_t resourceId = FFX_FRAMEINTERPOLATION_RESOURCE_IDENTIFIER_PREVIOUS_INTERPOLATION_SOURCE; + auto context = reinterpret_cast(&m_Context); + + // Create an exact texture copy but with the new format + auto newCopyDescription = context->contextDescription.backendInterface.fpGetResourceDescription( + &context->contextDescription.backendInterface, + context->srvResources[resourceId]); + + newCopyDescription.format = NewFormat; + + const FfxCreateResourceDescription createResourceDescription = { FFX_HEAP_TYPE_DEFAULT, + newCopyDescription, + FFX_RESOURCE_STATE_UNORDERED_ACCESS, + 0, + nullptr, + L"FI_PreviousInterpolationSourceHACK", + resourceId }; + + FFX_RETURN_ON_FAIL(context->contextDescription.backendInterface.fpCreateResource( + &context->contextDescription.backendInterface, + &createResourceDescription, + context->effectContextId, + &m_HackPreviousInterpolationSource)); + + m_OriginalPreviousInterpolationSource = context->srvResources[resourceId]; + context->srvResources[resourceId] = m_HackPreviousInterpolationSource; + context->uavResources[resourceId] = m_HackPreviousInterpolationSource; + + m_ResourceCreationHackActive = true; + return FFX_OK; +} diff --git a/source/maindll/FFInterpolator.h b/source/maindll/FFInterpolator.h new file mode 100644 index 0000000..315603c --- /dev/null +++ b/source/maindll/FFInterpolator.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include +#include +#include "FFXCommon.h" + +struct FFInterpolatorDispatchParameters +{ + FfxCommandList CommandList; + + FfxDimensions2D RenderSize; + FfxDimensions2D OutputSize; + + FfxResource InputColorBuffer; + FfxResource InputHUDLessColorBuffer; + FfxResource InputDilatedDepth; + FfxResource InputDilatedMotionVectors; + FfxResource InputReconstructedPreviousNearDepth; + + FfxResource InputOpticalFlowVector; + FfxResource InputOpticalFlowSceneChangeDetection; + FfxDimensions2D OpticalFlowBufferSize; + FfxFloatCoords2D OpticalFlowScale; + int OpticalFlowBlockSize; + + FfxResource OutputColorBuffer; + + bool HDR; + bool DepthInverted; + bool Reset; + bool DebugTearLines; + bool DebugView; + + float CameraNear; + float CameraFar; + float CameraFovAngleVertical; + float ViewSpaceToMetersFactor; + FfxFloatCoords2D MinMaxLuminance; +}; + +class FFInterpolator +{ +private: + const uint32_t m_MaxRenderWidth; + const uint32_t m_MaxRenderHeight; + + FfxSurfaceFormat m_InitialBackBufferFormat = {}; + + FfxInterface m_BackendInterface = {}; + uint32_t m_EffectContextId = 0; + + FfxFrameInterpolationContext m_Context = {}; + bool m_ContextCreated = false; + + FfxResourceInternal m_HackPreviousInterpolationSource = {}; + FfxResourceInternal m_OriginalPreviousInterpolationSource = {}; + bool m_ResourceCreationHackActive = false; + +public: + FFInterpolator(const FfxInterface& BackendInterface, uint32_t MaxRenderWidth, uint32_t MaxRenderHeight); + FFInterpolator(const FFInterpolator&) = delete; + FFInterpolator& operator=(const FFInterpolator&) = delete; + ~FFInterpolator(); + + FfxErrorCode Dispatch(const FFInterpolatorDispatchParameters& Parameters); + +private: + FfxErrorCode InternalDeferredSetupContext(const FFInterpolatorDispatchParameters& Parameters); + FfxErrorCode InternalSwapResources(FfxSurfaceFormat NewFormat); +};