// 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. #pragma once #define USE_FFX_API 1 #include "render/rendermodule.h" #include "core/framework.h" #include "core/uimanager.h" #include "taa/taarendermodule.h" #include "translucency/translucencyrendermodule.h" #include "tonemapping/tonemappingrendermodule.h" #include #include #include #include namespace cauldron { class Texture; class ParameterSet; class ResourceView; class RootSignature; class UIRenderModule; } class FSRRenderModule : public cauldron::RenderModule { enum UpscalerType { Upscaler_Native, Upscaler_FSRAPI, } UpscalerType; public: FSRRenderModule() : RenderModule(L"FSRApiRenderModule"), m_SafetyMarginInMs(0.1f), m_VarianceFactor (0.1f), m_AllowHybridSpin (false), m_HybridSpinTime(2), m_AllowWaitForSingleObjectOnFence(false), framePacingTuning { m_SafetyMarginInMs, m_VarianceFactor, m_AllowHybridSpin, m_HybridSpinTime, m_AllowWaitForSingleObjectOnFence } {} virtual ~FSRRenderModule(); void Init(const json& initData); void EnableModule(bool enabled) override; void OnPreFrame() override; /** * @brief Setup parameters that the FSR API needs this frame and then call the FFX Dispatch. */ void Execute(double deltaTime, cauldron::CommandList* pCmdList) override; void PreTransCallback(double deltaTime, cauldron::CommandList* pCmdList); void PostTransCallback(double deltaTime, cauldron::CommandList* pCmdList); /** * @brief Recreate the FSR API Context to resize internal resources. Called by the framework when the resolution changes. */ void OnResize(const cauldron::ResolutionInfo& resInfo) override; /** * @brief Init UI. */ void InitUI(cauldron::UISection* uiSection); /** * @brief Returns whether or not FSR requires sample-side re-initialization. */ bool NeedsReInit() const { return m_NeedReInit; } /** * @brief Clears FSR re-initialization flag. */ void ClearReInit() { m_NeedReInit = false; } void SetFilter(int32_t method) { m_UpscaleMethod = method; if (m_IsNonNative) m_CurScale = m_ScalePreset; m_IsNonNative = (m_UpscaleMethod != Upscaler_Native); m_ScalePreset = m_IsNonNative ? m_CurScale : FSRScalePreset::NativeAA; UpdatePreset((int32_t*)&m_ScalePreset); } private: enum class FSRScalePreset { NativeAA = 0, // 1.0f Quality, // 1.5f Balanced, // 1.7f Performance, // 2.f UltraPerformance, // 3.f Custom // 1.f - 3.f range }; enum class FSRMaskMode { Disabled = 0, Manual, Auto }; const float cMipBias[static_cast(FSRScalePreset::Custom)] = { std::log2f(1.f / 1.0f) - 1.f + std::numeric_limits::epsilon(), std::log2f(1.f / 1.5f) - 1.f + std::numeric_limits::epsilon(), std::log2f(1.f / 1.7f) - 1.f + std::numeric_limits::epsilon(), std::log2f(1.f / 2.0f) - 1.f + std::numeric_limits::epsilon(), std::log2f(1.f / 3.0f) - 1.f + std::numeric_limits::epsilon() }; static void FfxMsgCallback(uint32_t type, const wchar_t* message); ffxReturnCode_t UiCompositionCallback(ffxCallbackDescFrameGenerationPresent*); void SwitchUpscaler(int32_t newUpscaler); void UpdatePreset(const int32_t* pOldPreset); void UpdateUpscaleRatio(const float* pOldRatio); void UpdateMipBias(const float* pOldBias); cauldron::ResolutionInfo UpdateResolution(uint32_t displayWidth, uint32_t displayHeight); void UpdateFSRContext(bool enabled); cauldron::UIRenderModule* m_pUIRenderModule = nullptr; cauldron::ResourceView* m_pRTResourceView = nullptr; int32_t m_UpscaleMethod = Upscaler_FSRAPI; int32_t m_UiUpscaleMethod = Upscaler_FSRAPI; FSRScalePreset m_CurScale = FSRScalePreset::Quality; FSRScalePreset m_ScalePreset = FSRScalePreset::Quality; float m_UpscaleRatio = 2.f; float m_LetterboxRatio = 1.f; float m_MipBias = cMipBias[static_cast(FSRScalePreset::Quality)]; FSRMaskMode m_MaskMode = FSRMaskMode::Manual; float m_Sharpness = 0.8f; uint32_t m_JitterIndex = 0; float m_JitterX = 0.f; float m_JitterY = 0.f; uint64_t m_FrameID = 0; bool m_IsNonNative = true; bool m_UpscaleRatioEnabled = false; bool m_UseMask = true; bool m_UseDistortionField = false; bool m_RCASSharpen = true; bool m_SharpnessEnabled = false; bool m_NeedReInit = false; bool m_FrameInterpolationAvailable = false; bool m_AsyncComputeAvailable = false; bool m_EnableMaskOptions = true; bool m_EnableWaitCallbackModeUI = true; bool m_FrameInterpolation = true; bool m_EnableAsyncCompute = true; bool m_AllowAsyncCompute = true; bool m_PendingEnableAsyncCompute = true; bool m_UseCallback = true; bool m_DrawFrameGenerationDebugTearLines = true; bool m_DrawFrameGenerationDebugResetIndicators = true; bool m_DrawFrameGenerationDebugPacingLines = false; bool m_DrawFrameGenerationDebugView = false; bool m_DrawUpscalerDebugView = false; bool m_PresentInterpolatedOnly = false; bool m_SimulatePresentSkip = false; bool m_ResetUpscale = false; bool m_ResetFrameInterpolation = false; bool m_DoublebufferInSwapchain = false; bool m_OfUiEnabled = true; // FFX API Context members std::vector m_FsrVersionIds; uint32_t m_FsrVersionIndex = 0; bool m_ffxBackendInitialized = false; ffx::Context m_UpscalingContext = nullptr; ffx::Context m_FrameGenContext = nullptr; ffx::Context m_SwapChainContext = nullptr; ffx::ConfigureDescFrameGeneration m_FrameGenerationConfig{}; // Backup UI elements std::vector m_UIElements{}; // weak ptr // FSR resources const cauldron::Texture* m_pColorTarget = nullptr; const cauldron::Texture* m_pTonemappedColorTarget = nullptr; const cauldron::Texture* m_pTempTexture = nullptr; const cauldron::Texture* m_pDepthTarget = nullptr; const cauldron::Texture* m_pMotionVectors = nullptr; const cauldron::Texture* m_pReactiveMask = nullptr; const cauldron::Texture* m_pCompositionMask = nullptr; const cauldron::Texture* m_pOpaqueTexture = nullptr; // Raster views for reactive/composition masks std::vector m_RasterViews = {}; cauldron::ResourceView* m_pUiTargetResourceView = nullptr; // For resolution updates std::function m_pUpdateFunc = nullptr; bool s_enableSoftwareMotionEstimation = true; int32_t s_uiRenderMode = 2; // Surfaces for different UI render modes uint32_t m_curUiTextureIndex = 0; const cauldron::Texture* m_pUiTexture[2] = {}; const cauldron::Texture* m_pHudLessTexture[2] = {}; const cauldron::Texture* m_pDistortionField[2] = {}; TAARenderModule* m_pTAARenderModule = nullptr; ToneMappingRenderModule* m_pToneMappingRenderModule = nullptr; TranslucencyRenderModule* m_pTransRenderModule = nullptr; //Set Constant Buffer KeyValue via Configure Context KeyValue API. Valid Post Context creation. int32_t m_UpscalerCBKey = 0; float m_UpscalerCBValue = 1.f; void SetUpscaleConstantBuffer(uint64_t key, float value); //Set Swapchain waitcallback via Configure Context KeyValue API int32_t m_waitCallbackMode = 0; //Set Swapchain Frame pacing Tuning float m_SafetyMarginInMs; // in Millisecond float m_VarianceFactor; // valid range [0.0,1.0] bool m_AllowHybridSpin; uint32_t m_HybridSpinTime; bool m_AllowWaitForSingleObjectOnFence; FfxApiSwapchainFramePacingTuning framePacingTuning; }; // alias to get sample.cpp to use this class. using FSRApiRenderModule = FSRRenderModule;