diff --git a/OptiScaler.ini b/OptiScaler.ini index 3a179428..90567ccd 100644 --- a/OptiScaler.ini +++ b/OptiScaler.ini @@ -267,6 +267,12 @@ ResourceFlip=auto ; true or false - Default (auto) is false ResourceFlipOffset=auto +; Always captures and swaps FSR-FG 3.1 swapchain with selected output +; This should fix double present call issue with +; games create but not use FSR-FG swapchain (Silent Hill f) +; true or false - Default (auto) is false +AlwaysCaptureFSRFGSwapchain=auto + ; ------------------------------------------------------- diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp index b1586e54..10b0bdb0 100644 --- a/OptiScaler/Config.cpp +++ b/OptiScaler/Config.cpp @@ -134,6 +134,8 @@ bool Config::Reload(std::filesystem::path iniPath) FGResourceFlip.set_from_config(readBool("OptiFG", "ResourceFlip")); FGResourceFlipOffset.set_from_config(readBool("OptiFG", "ResourceFlipOffset")); + + FGAlwaysCaptureFSRFGSwapchain.set_from_config(readBool("OptiFG", "AlwaysCaptureFSRFGSwapchain")); } { @@ -730,6 +732,9 @@ bool Config::SaveIni() ini.SetValue("OptiFG", "ResourceFlip", GetBoolValue(Instance()->FGResourceFlip.value_for_config()).c_str()); ini.SetValue("OptiFG", "ResourceFlipOffset", GetBoolValue(Instance()->FGResourceFlipOffset.value_for_config()).c_str()); + + ini.SetValue("OptiFG", "AlwaysCaptureFSRFGSwapchain", + GetBoolValue(Instance()->FGAlwaysCaptureFSRFGSwapchain.value_for_config()).c_str()); } // Framerate diff --git a/OptiScaler/Config.h b/OptiScaler/Config.h index 18fd19d7..2da7cc7f 100644 --- a/OptiScaler/Config.h +++ b/OptiScaler/Config.h @@ -400,6 +400,7 @@ class Config CustomOptional FGMakeDepthCopy { true }; CustomOptional FGResourceFlip { false }; CustomOptional FGResourceFlipOffset { false }; + CustomOptional FGAlwaysCaptureFSRFGSwapchain { false }; CustomOptional FGRectLeft; CustomOptional FGRectTop; diff --git a/OptiScaler/dllmain.cpp b/OptiScaler/dllmain.cpp index a69efc35..a9475be5 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -1054,6 +1054,10 @@ static void CheckQuirks() if (quirks & GameQuirk::UseFSR2PatternMatching && !Config::Instance()->Fsr2Pattern.has_value()) Config::Instance()->Fsr2Pattern.set_volatile_value(true); + if (quirks & GameQuirk::AlwaysCaptureFSRFGSwapchain && + !Config::Instance()->FGAlwaysCaptureFSRFGSwapchain.has_value()) + Config::Instance()->FGAlwaysCaptureFSRFGSwapchain.set_volatile_value(true); + State::Instance().gameQuirks = quirks; } diff --git a/OptiScaler/inputs/FfxApi_Dx12.cpp b/OptiScaler/inputs/FfxApi_Dx12.cpp index f83ba54a..e10d3e1a 100644 --- a/OptiScaler/inputs/FfxApi_Dx12.cpp +++ b/OptiScaler/inputs/FfxApi_Dx12.cpp @@ -279,8 +279,9 @@ ffxReturnCode_t ffxCreateContext_Dx12(ffxContext* context, ffxCreateContextDescH // It would crash the games which uses swapchain for FG if (IsFGType(desc->type) && (State::Instance().activeFgInput == FGInput::FSRFG || - ((desc->type == 0x30005 || desc->type == 0x30006) && State::Instance().activeFgInput == FGInput::Upscaler && - State::Instance().activeFgOutput != FGOutput::NoFG && State::Instance().activeFgOutput != FGOutput::Nukems))) + (Config::Instance()->FGAlwaysCaptureFSRFGSwapchain.value_or_default() && + State::Instance().activeFgOutput != FGOutput::NoFG && State::Instance().activeFgOutput != FGOutput::Nukems && + (desc->type == 0x30005 || desc->type == 0x30006)))) { auto result = ffxCreateContext_Dx12FG(context, desc, memCb); diff --git a/OptiScaler/misc/Quirks.h b/OptiScaler/misc/Quirks.h index 3fed767e..00831730 100644 --- a/OptiScaler/misc/Quirks.h +++ b/OptiScaler/misc/Quirks.h @@ -26,6 +26,7 @@ enum class GameQuirk : uint64_t DisableVsyncOverride, UseNtDllHooks, UseFSR2PatternMatching, + AlwaysCaptureFSRFGSwapchain, // Quirks that are applied deeper in code CyberpunkHudlessStateOverride, @@ -69,6 +70,10 @@ static const QuirkEntry quirkTable[] = { QUIRK_ENTRY("visionsofmana-win64-shipping.exe", GameQuirk::UseFSR2PatternMatching, GameQuirk::DisableDxgiSpoofing), QUIRK_ENTRY("visionsofmana-wingdk-shipping.exe", GameQuirk::UseFSR2PatternMatching, GameQuirk::DisableDxgiSpoofing), + // Silent Hill f + QUIRK_ENTRY("shf-win64-shipping.exe", GameQuirk::AlwaysCaptureFSRFGSwapchain), + QUIRK_ENTRY("shf-wingdk-shipping.exe", GameQuirk::AlwaysCaptureFSRFGSwapchain), + // Path of Exile 2 QUIRK_ENTRY("pathofexile.exe", GameQuirk::LoadD3D12Manually), QUIRK_ENTRY("pathofexile_x64.exe", GameQuirk::LoadD3D12Manually), @@ -309,6 +314,8 @@ static void printQuirks(flag_set& quirks) spdlog::info("Quirk: Using NTdll hooks instead of kernel ones"); if (quirks & GameQuirk::UseFSR2PatternMatching) spdlog::info("Quirk: Use FSR2 pattern matching"); + if (quirks & GameQuirk::AlwaysCaptureFSRFGSwapchain) + spdlog::info("Quirk: Always capture FSR-FG swapchain"); return; }