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 442a2969..a9475be5 100644 --- a/OptiScaler/dllmain.cpp +++ b/OptiScaler/dllmain.cpp @@ -1051,6 +1051,13 @@ static void CheckQuirks() if (quirks & GameQuirk::UseNtDllHooks && !Config::Instance()->UseNtdllHooks.has_value()) Config::Instance()->UseNtdllHooks.set_volatile_value(true); + 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/framegen/xefg/XeFG_Dx12.cpp b/OptiScaler/framegen/xefg/XeFG_Dx12.cpp index ba1d1b36..4ba823fb 100644 --- a/OptiScaler/framegen/xefg/XeFG_Dx12.cpp +++ b/OptiScaler/framegen/xefg/XeFG_Dx12.cpp @@ -221,15 +221,30 @@ bool XeFG_Dx12::CreateSwapchain(IDXGIFactory* factory, ID3D12CommandQueue* cmdQu HWND hwnd = desc->OutputWindow; DXGI_SWAP_CHAIN_DESC1 scDesc {}; - scDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; // No info + scDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; // No info scDesc.BufferCount = desc->BufferCount; scDesc.BufferUsage = desc->BufferUsage; scDesc.Flags = desc->Flags; scDesc.Format = desc->BufferDesc.Format; scDesc.Height = desc->BufferDesc.Height; scDesc.SampleDesc = desc->SampleDesc; - scDesc.Scaling = DXGI_SCALING_NONE; // No info - scDesc.Stereo = false; // No info + + switch (desc->BufferDesc.Scaling) + { + case DXGI_MODE_SCALING_CENTERED: + scDesc.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH; + break; + + case DXGI_MODE_SCALING_STRETCHED: + scDesc.Scaling = DXGI_SCALING_STRETCH; + break; + + case DXGI_MODE_SCALING_UNSPECIFIED: + scDesc.Scaling = DXGI_SCALING_NONE; + break; + } + + scDesc.Stereo = false; // No info scDesc.SwapEffect = desc->SwapEffect; scDesc.Width = desc->BufferDesc.Width; diff --git a/OptiScaler/fsr4/FSR4Upgrade.cpp b/OptiScaler/fsr4/FSR4Upgrade.cpp index 7ad937b9..e1898091 100644 --- a/OptiScaler/fsr4/FSR4Upgrade.cpp +++ b/OptiScaler/fsr4/FSR4Upgrade.cpp @@ -136,6 +136,8 @@ void CheckForGPU() continue; } + Config::Instance()->Fsr4Update.set_volatile_value(false); + State::Instance().skipSpoofing = true; result = adapter->GetDesc(&adapterDesc); State::Instance().skipSpoofing = false; diff --git a/OptiScaler/hooks/DxgiFactory_Hooks.cpp b/OptiScaler/hooks/DxgiFactory_Hooks.cpp index 51314814..062bf692 100644 --- a/OptiScaler/hooks/DxgiFactory_Hooks.cpp +++ b/OptiScaler/hooks/DxgiFactory_Hooks.cpp @@ -214,22 +214,33 @@ HRESULT DxgiFactoryHooks::CreateSwapChain(IDXGIFactory* realFactory, IUnknown* p State::Instance().realExclusiveFullscreen = !pDesc->Windowed; // Check for SL proxy, get real queue - ID3D12CommandQueue* real = nullptr; - if (!Util::CheckForRealObject(__FUNCTION__, pDevice, (IUnknown**) &real)) - real = (ID3D12CommandQueue*) pDevice; - - State::Instance().currentCommandQueue = real; - - // Create FG SwapChain + ID3D12CommandQueue* cq = nullptr; + IUnknown* real = nullptr; HRESULT FGSCResult = E_NOTIMPL; - if (!_skipFGSwapChainCreation) - { - _skipFGSwapChainCreation = true; - FGSCResult = FGHooks::CreateSwapChain(realFactory, real, pDesc, ppSwapChain); - _skipFGSwapChainCreation = false; - if (FGSCResult == S_OK) - return FGSCResult; + if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + cq->Release(); + + if (!Util::CheckForRealObject(__FUNCTION__, cq, &real)) + real = cq; + + State::Instance().currentCommandQueue = (ID3D12CommandQueue*) real; + + // Create FG SwapChain + if (!_skipFGSwapChainCreation) + { + _skipFGSwapChainCreation = true; + FGSCResult = FGHooks::CreateSwapChain(realFactory, real, pDesc, ppSwapChain); + _skipFGSwapChainCreation = false; + + if (FGSCResult == S_OK) + return FGSCResult; + } + } + else + { + LOG_INFO("Failed to get ID3D12CommandQueue from pDevice, creating Dx11 swapchain!"); } HRESULT result = E_FAIL; @@ -397,23 +408,34 @@ HRESULT DxgiFactoryHooks::CreateSwapChainForHwnd(IDXGIFactory2* realFactory, IUn State::Instance().realExclusiveFullscreen = pFullscreenDesc != nullptr && !pFullscreenDesc->Windowed; // Check for SL proxy, get real queue - ID3D12CommandQueue* real = nullptr; - if (!Util::CheckForRealObject(__FUNCTION__, pDevice, (IUnknown**) &real)) - real = (ID3D12CommandQueue*) pDevice; - - State::Instance().currentCommandQueue = real; - - // Create FG SwapChain + ID3D12CommandQueue* cq = nullptr; + IUnknown* real = nullptr; HRESULT FGSCResult = E_NOTIMPL; - if (!_skipFGSwapChainCreation) - { - _skipFGSwapChainCreation = true; - FGSCResult = FGHooks::CreateSwapChainForHwnd(realFactory, real, hWnd, pDesc, pFullscreenDesc, pRestrictToOutput, - ppSwapChain); - _skipFGSwapChainCreation = false; - if (FGSCResult == S_OK) - return FGSCResult; + if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + cq->Release(); + + if (!Util::CheckForRealObject(__FUNCTION__, cq, &real)) + real = cq; + + State::Instance().currentCommandQueue = (ID3D12CommandQueue*) real; + + // Create FG SwapChain + if (!_skipFGSwapChainCreation) + { + _skipFGSwapChainCreation = true; + FGSCResult = FGHooks::CreateSwapChainForHwnd(realFactory, real, hWnd, pDesc, pFullscreenDesc, + pRestrictToOutput, ppSwapChain); + _skipFGSwapChainCreation = false; + + if (FGSCResult == S_OK) + return FGSCResult; + } + } + else + { + LOG_INFO("Failed to get ID3D12CommandQueue from pDevice, creating Dx11 swapchain!"); } HRESULT result = E_FAIL; @@ -541,11 +563,17 @@ HRESULT DxgiFactoryHooks::CreateSwapChainForCoreWindow(IDXGIFactory2* realFactor State::Instance().SCLastFlags = pDesc->Flags; State::Instance().realExclusiveFullscreen = false; - ID3D12CommandQueue* realQ = nullptr; - if (!Util::CheckForRealObject(__FUNCTION__, pDevice, (IUnknown**) &realQ)) - realQ = (ID3D12CommandQueue*) pDevice; + ID3D12CommandQueue* cq = nullptr; + IUnknown* real = nullptr; + if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) == S_OK) + { + cq->Release(); - State::Instance().currentCommandQueue = realQ; + if (!Util::CheckForRealObject(__FUNCTION__, cq, &real)) + real = cq; + + State::Instance().currentCommandQueue = (ID3D12CommandQueue*) real; + } State::Instance().skipDxgiLoadChecks = true; auto result = o_CreateSwapChainForCoreWindow(realFactory, pDevice, pWindow, pDesc, pRestrictToOutput, ppSwapChain); diff --git a/OptiScaler/hooks/FG_Hooks.cpp b/OptiScaler/hooks/FG_Hooks.cpp index 2781facc..816e6053 100644 --- a/OptiScaler/hooks/FG_Hooks.cpp +++ b/OptiScaler/hooks/FG_Hooks.cpp @@ -52,12 +52,18 @@ HRESULT FGHooks::CreateSwapChain(IDXGIFactory* pFactory, IUnknown* pDevice, DXGI IDXGISwapChain** ppSwapChain) { if (!CheckForFGStatus()) + { + LOG_ERROR("Can't init FG Feature, invalid status!"); return E_NOINTERFACE; + } // Check if it's Dx12 ID3D12CommandQueue* cq = nullptr; if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) != S_OK) + { + LOG_ERROR("FG Feature requires D3D12 Command Queue!"); return E_INVALIDARG; + } cq->Release(); @@ -115,12 +121,18 @@ HRESULT FGHooks::CreateSwapChainForHwnd(IDXGIFactory* pFactory, IUnknown* pDevic IDXGIOutput* pRestrictToOutput, IDXGISwapChain1** ppSwapChain) { if (!CheckForFGStatus()) + { + LOG_ERROR("Can't init FG Feature, invalid status!"); return E_NOINTERFACE; + } // Check if it's Dx12 ID3D12CommandQueue* cq = nullptr; if (pDevice->QueryInterface(IID_PPV_ARGS(&cq)) != S_OK) + { + LOG_ERROR("FG Feature requires D3D12 Command Queue!"); return E_INVALIDARG; + } cq->Release(); diff --git a/OptiScaler/hudfix/Hudfix_Dx12.cpp b/OptiScaler/hudfix/Hudfix_Dx12.cpp index af918931..80a8afe5 100644 --- a/OptiScaler/hudfix/Hudfix_Dx12.cpp +++ b/OptiScaler/hudfix/Hudfix_Dx12.cpp @@ -329,11 +329,12 @@ void Hudfix_Dx12::HudlessFound(ID3D12GraphicsCommandList* cmdList) std::lock_guard lock(_counterMutex); - if (_captureCounter[GetIndex()] > 1000) + auto index = GetIndex(); + if (_captureCounter[index] > 1000) return; // Set it above 1000 to prvent capture - _captureCounter[GetIndex()] = 9999; + _captureCounter[index] = 9999; // auto fg = State::Instance().currentFG; // if (fg != nullptr) @@ -583,13 +584,13 @@ bool Hudfix_Dx12::CheckForHudless(std::string callerName, ID3D12GraphicsCommandL // Using state D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE as skip flag if (state != D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE) - ResourceBarrier(cmdList, resource->buffer, state, D3D12_RESOURCE_STATE_COPY_SOURCE); + ResourceBarrier(cmdList, resource->buffer, resource->state, D3D12_RESOURCE_STATE_COPY_SOURCE); cmdList->CopyResource(_captureBuffer[fIndex], resource->buffer); // Using state D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE as skip flag if (state != D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE) - ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, state); + ResourceBarrier(cmdList, resource->buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, resource->state); LOG_DEBUG("Copy created"); } 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/inputs/NVNGX_DLSS_Dx11.cpp b/OptiScaler/inputs/NVNGX_DLSS_Dx11.cpp index b92ac414..65e0cace 100644 --- a/OptiScaler/inputs/NVNGX_DLSS_Dx11.cpp +++ b/OptiScaler/inputs/NVNGX_DLSS_Dx11.cpp @@ -79,7 +79,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_Init_Ext(unsigned long long InApp if (InDevice) D3D11Device = InDevice; - State::Instance().api = DX11; State::Instance().currentD3D11Device = InDevice; State::Instance().NvngxDx11Inited = true; @@ -422,6 +421,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D11_CreateFeature(ID3D11DeviceContext } } + State::Instance().api = DX11; auto deviceContext = Dx11Contexts[handleId].feature.get(); *OutHandle = deviceContext->Handle(); diff --git a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp index 3fcc032d..f790eaf7 100644 --- a/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp +++ b/OptiScaler/inputs/NVNGX_DLSS_Dx12.cpp @@ -182,7 +182,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_Init_Ext(unsigned long long InApp D3D12Device = InDevice; - State::Instance().api = DX12; State::Instance().currentD3D12Device = InDevice; if (!State::Instance().isWorkingAsNvngx) @@ -578,6 +577,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_CreateFeature(ID3D12GraphicsComma } // Create feature + State::Instance().api = DX12; auto handleId = IFeature::GetNextHandleId(); LOG_INFO("HandleId: {0}", handleId); diff --git a/OptiScaler/inputs/NVNGX_DLSS_Vk.cpp b/OptiScaler/inputs/NVNGX_DLSS_Vk.cpp index e63cb5de..81f83c0e 100644 --- a/OptiScaler/inputs/NVNGX_DLSS_Vk.cpp +++ b/OptiScaler/inputs/NVNGX_DLSS_Vk.cpp @@ -134,7 +134,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_Init_Ext2( vkGIPA = vkGetInstanceProcAddr; } - State::Instance().api = Vulkan; State::Instance().currentVkDevice = InDevice; UpscalerTimeVk::Init(InDevice, InPD); @@ -706,6 +705,7 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_VULKAN_CreateFeature1(VkDevice InDevice } } + State::Instance().api = Vulkan; auto deviceContext = VkContexts[handleId].feature.get(); *OutHandle = deviceContext->Handle(); diff --git a/OptiScaler/menu/menu_common.cpp b/OptiScaler/menu/menu_common.cpp index 51166b07..954778e5 100644 --- a/OptiScaler/menu/menu_common.cpp +++ b/OptiScaler/menu/menu_common.cpp @@ -1464,8 +1464,7 @@ bool MenuCommon::RenderMenu() inputFG = false; if (state.activeFgInput != FGInput::NoFG && state.activeFgOutput != FGOutput::NoFG && - state.swapchainApi != API::DX11 && - (state.swapchainApi != API::Vulkan || state.activeFgInput == FGInput::Nukems)) + (state.currentFGSwapchain != nullptr || state.activeFgInput == FGInput::Nukems)) { Config::Instance()->FGEnabled = !Config::Instance()->FGEnabled.value_or_default(); @@ -2900,7 +2899,7 @@ bool MenuCommon::RenderMenu() // fgInputDesc[optiFgIndex] = "Old overlay menu is unsupported"; //} // else if (state.swapchainApi != DX12) - if (state.swapchainApi != DX12 || state.api != DX12) + if (state.currentFGSwapchain == nullptr || state.api != DX12) { disabledMaskInput[optiFgIndex] = true; fgInputDesc[optiFgIndex] = "Unsupported API"; @@ -2937,7 +2936,7 @@ bool MenuCommon::RenderMenu() if (Config::Instance()->FGInput.value_or_default() == FGInput::DLSSG) Config::Instance()->FGInput.reset(); } - else if (state.swapchainApi != DX12) + else if (state.currentFGSwapchain == nullptr) { disabledMaskInput[dlssgInputIndex] = true; fgInputDesc[dlssgInputIndex] = "Unsupported API"; @@ -2945,7 +2944,7 @@ bool MenuCommon::RenderMenu() // FSRFG inputs requirements auto constexpr fsrfgInputIndex = (uint32_t) FGInput::FSRFG; - if (state.swapchainApi != DX12) + if (state.currentFGSwapchain == nullptr) { disabledMaskInput[fsrfgInputIndex] = true; fgInputDesc[fsrfgInputIndex] = "Unsupported API"; @@ -2984,14 +2983,15 @@ bool MenuCommon::RenderMenu() // Nukem's FG mod requirements auto constexpr nukemsInputIndex = (uint32_t) FGInput::Nukems; auto constexpr nukemsOutputIndex = (uint32_t) FGOutput::Nukems; - if (state.swapchainApi == DX11) - { - disabledMaskInput[nukemsInputIndex] = true; - fgInputDesc[nukemsInputIndex] = "Unsupported API"; - disabledMaskOutput[nukemsOutputIndex] = true; - fgOutputDesc[nukemsOutputIndex] = "Unsupported API"; - } - else if (state.isWorkingAsNvngx) + // if (state.swapchainApi == DX11) + //{ + // disabledMaskInput[nukemsInputIndex] = true; + // fgInputDesc[nukemsInputIndex] = "Unsupported API"; + // disabledMaskOutput[nukemsOutputIndex] = true; + // fgOutputDesc[nukemsOutputIndex] = "Unsupported API"; + // } + // else + if (state.isWorkingAsNvngx) { disabledMaskInput[nukemsInputIndex] = true; fgInputDesc[nukemsInputIndex] = "Unsupported Opti working mode"; @@ -3009,7 +3009,7 @@ bool MenuCommon::RenderMenu() // FSR FG / XeFG output requirements auto constexpr fsrfgOutputIndex = (uint32_t) FGOutput::FSRFG; auto constexpr xefgOutputIndex = (uint32_t) FGOutput::XeFG; - if (state.swapchainApi != DX12) + if (state.currentFGSwapchain == nullptr) { disabledMaskOutput[fsrfgOutputIndex] = true; fgOutputDesc[fsrfgOutputIndex] = "Unsupported API"; @@ -3023,7 +3023,7 @@ bool MenuCommon::RenderMenu() Config::Instance()->FGOutput = Config::Instance()->FGOutput.value_or_default(); // need to have a value before combo - if (state.swapchainApi != DX11) + if (state.currentFGSwapchain != nullptr) { ImGui::SeparatorText("Frame Generation"); @@ -3148,7 +3148,7 @@ bool MenuCommon::RenderMenu() // FSR FG controls if (state.activeFgOutput == FGOutput::FSRFG && state.activeFgInput != FGInput::NoFG && - !state.isWorkingAsNvngx && state.swapchainApi == DX12) + !state.isWorkingAsNvngx && state.currentFGSwapchain != nullptr) { if (state.activeFgInput != FGInput::Upscaler || (currentFeature != nullptr && !currentFeature->IsFrozen()) && FfxApiProxy::IsFGReady()) @@ -3346,7 +3346,7 @@ bool MenuCommon::RenderMenu() // XeFG controls if (state.activeFgOutput == FGOutput::XeFG && state.activeFgInput != FGInput::NoFG && - !state.isWorkingAsNvngx && state.swapchainApi == DX12) + !state.isWorkingAsNvngx && state.currentFGSwapchain != nullptr) { if (state.activeFgInput != FGInput::Upscaler || (currentFeature != nullptr && !currentFeature->IsFrozen()) && XeFGProxy::InitXeFG()) @@ -3518,7 +3518,7 @@ bool MenuCommon::RenderMenu() } // OptiFG - if (state.api == DX12 && state.swapchainApi == DX12 && !state.isWorkingAsNvngx && + if (state.api == DX12 && state.currentFGSwapchain != nullptr && !state.isWorkingAsNvngx && state.activeFgInput == FGInput::Upscaler) { SeparatorWithHelpMarker("Frame Generation (OptiFG)", "Using upscaler data for FG"); @@ -3745,7 +3745,7 @@ bool MenuCommon::RenderMenu() } // Nukems Mod - if (state.swapchainApi != DX11 && !state.isWorkingAsNvngx && state.activeFgInput == FGInput::Nukems && + if (!state.isWorkingAsNvngx && state.activeFgInput == FGInput::Nukems && state.activeFgOutput == FGOutput::Nukems) { SeparatorWithHelpMarker("Frame Generation (FSR-FG via Nukem's DLSSG)", @@ -3762,8 +3762,8 @@ bool MenuCommon::RenderMenu() } else if (!ReflexHooks::isDlssgDetected()) { - ImGui::Text("Please select DLSS Frame Generation in the game options\nYou might need to select " - "DLSS first"); + ImGui::Text("Please select DLSS Frame Generation in the game options\n" + "You might need to select DLSS first"); } if (state.swapchainApi == DX12) @@ -3812,7 +3812,7 @@ bool MenuCommon::RenderMenu() } // FSR-FG Inputs - if (state.swapchainApi == DX12 && !state.isWorkingAsNvngx && + if (state.currentFGSwapchain != nullptr && !state.isWorkingAsNvngx && (state.activeFgInput == FGInput::FSRFG || state.activeFgInput == FGInput::FSRFG30)) { SeparatorWithHelpMarker("Frame Generation (FSR-FG Inputs)", "Select FSR-FG in-game"); @@ -3839,7 +3839,8 @@ bool MenuCommon::RenderMenu() } // Streamline FG Inputs - if (state.swapchainApi == DX12 && !state.isWorkingAsNvngx && state.activeFgInput == FGInput::DLSSG) + if (state.currentFGSwapchain != nullptr && !state.isWorkingAsNvngx && + state.activeFgInput == FGInput::DLSSG) { SeparatorWithHelpMarker("Frame Generation (Streamline FG Inputs)", "Select DLSS FG in-game"); diff --git a/OptiScaler/menu/menu_overlay_dx.cpp b/OptiScaler/menu/menu_overlay_dx.cpp index 47f68511..794b7096 100644 --- a/OptiScaler/menu/menu_overlay_dx.cpp +++ b/OptiScaler/menu/menu_overlay_dx.cpp @@ -583,7 +583,7 @@ void MenuOverlayDx::Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT // Process window handle changed, update base if (MenuOverlayBase::Handle() != hWnd) { - LOG_DEBUG("Handle changed"); + LOG_DEBUG("Handle changed {:X} -> {:X}", (size_t) MenuOverlayBase::Handle(), (size_t) hWnd); if (MenuOverlayBase::IsInited()) MenuOverlayBase::Shutdown(); diff --git a/OptiScaler/misc/Quirks.h b/OptiScaler/misc/Quirks.h index 4f5a5bff..97315f40 100644 --- a/OptiScaler/misc/Quirks.h +++ b/OptiScaler/misc/Quirks.h @@ -25,6 +25,8 @@ enum class GameQuirk : uint64_t SkipFirst10Frames, DisableVsyncOverride, UseNtDllHooks, + UseFSR2PatternMatching, + AlwaysCaptureFSRFGSwapchain, // Quirks that are applied deeper in code CyberpunkHudlessStateOverride, @@ -63,6 +65,15 @@ static const QuirkEntry quirkTable[] = { // No Man's Sky QUIRK_ENTRY("nms.exe", GameQuirk::KernelBaseHooks, GameQuirk::VulkanDLSSBarrierFixup), + // Visions of Mana + // Use FSR2 Pattern Matching to fix broken FSR2 detection + 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), @@ -304,6 +315,10 @@ static void printQuirks(flag_set& quirks) spdlog::info("Quirk: Skipping D3D11 feature level elevation, native FSR3.1 will be disabled!"); if (quirks & GameQuirk::UseNtDllHooks) 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; } diff --git a/OptiScaler/resource_tracking/ResTrack_dx12.cpp b/OptiScaler/resource_tracking/ResTrack_dx12.cpp index 00382a8f..bf7890cd 100644 --- a/OptiScaler/resource_tracking/ResTrack_dx12.cpp +++ b/OptiScaler/resource_tracking/ResTrack_dx12.cpp @@ -157,9 +157,9 @@ bool ResTrack_Dx12::CheckResource(ID3D12Resource* resource) resDesc.Height <= scDesc.BufferDesc.Height + 32 && resDesc.Width >= scDesc.BufferDesc.Width - 32 && resDesc.Width <= scDesc.BufferDesc.Width + 32; - LOG_TRACK("Resource: {}x{} ({}), Swapchain: {}x{} ({}), Relaxed Result: {}", resDesc.Width, resDesc.Height, - (UINT) resDesc.Format, scDesc.BufferDesc.Width, scDesc.BufferDesc.Height, - (UINT) scDesc.BufferDesc.Format, result); + // LOG_TRACK("Resource: {}x{} ({}), Swapchain: {}x{} ({}), Relaxed Result: {}", resDesc.Width, resDesc.Height, + // (UINT) resDesc.Format, scDesc.BufferDesc.Width, scDesc.BufferDesc.Height, + // (UINT) scDesc.BufferDesc.Format, result); return result; } @@ -1150,8 +1150,9 @@ void ResTrack_Dx12::hkSetGraphicsRootDescriptorTable(ID3D12GraphicsCommandList* fgPossibleHudless[fIndex].insert_or_assign(This, newMap); } - LOG_TRACK("CmdList: {:X}, AddRef Resource: {:X}, Desc: {:X}", (size_t) This, - (size_t) capturedBuffer->buffer, BaseDescriptor.ptr); + LOG_TRACK("CmdList: {:X}, AddRef Resource: {:X}, Desc: {:X}, Format: {}", (size_t) This, + (size_t) capturedBuffer->buffer, BaseDescriptor.ptr, (UINT) capturedBuffer->format); + fgPossibleHudless[fIndex][This].insert_or_assign(capturedBuffer->buffer, *capturedBuffer); } } while (false); @@ -1182,6 +1183,7 @@ void ResTrack_Dx12::hkOMSetRenderTargets(ID3D12GraphicsCommandList* This, UINT N { LOG_DEBUG_ONLY("Menu cmdlist: {} || fgCommandList: {}", This == MenuOverlayDx::MenuCommandList(), IsFGCommandList(This)); + o_OMSetRenderTargets(This, NumRenderTargetDescriptors, pRenderTargetDescriptors, RTsSingleHandleToDescriptorRange, pDepthStencilDescriptor); return; @@ -1229,7 +1231,8 @@ void ResTrack_Dx12::hkOMSetRenderTargets(ID3D12GraphicsCommandList* This, UINT N { if (Hudfix_Dx12::CheckForHudless(__FUNCTION__, This, capturedBuffer, capturedBuffer->state)) { - LOG_TRACK("Hudless Resource: {:X}, Desc: {:X}", (size_t) capturedBuffer->buffer, handle.ptr); + LOG_TRACK("CmdList: {:X}, Hudless Resource: {:X}, Format: {} Desc: {:X}", (size_t) This, + (size_t) capturedBuffer->buffer, (UINT) capturedBuffer->format, handle.ptr); break; } } diff --git a/OptiScaler/resource_tracking/ResTrack_dx12.h b/OptiScaler/resource_tracking/ResTrack_dx12.h index c7d7c53d..58d1d767 100644 --- a/OptiScaler/resource_tracking/ResTrack_dx12.h +++ b/OptiScaler/resource_tracking/ResTrack_dx12.h @@ -135,10 +135,12 @@ typedef struct HeapInfo #ifdef DEBUG_TRACKING TestResource(&setInfo); #endif - - DetachFromOldResource(index); - info[index] = setInfo; - AttachToNewResource(index); + if (info[index].buffer != setInfo.buffer) + { + DetachFromOldResource(index); + info[index] = setInfo; + AttachToNewResource(index); + } } void SetByGpuHandle(SIZE_T gpuHandle, ResourceInfo setInfo) const @@ -152,9 +154,12 @@ typedef struct HeapInfo TestResource(&setInfo); #endif - DetachFromOldResource(index); - info[index] = setInfo; - AttachToNewResource(index); + if (info[index].buffer != setInfo.buffer) + { + DetachFromOldResource(index); + info[index] = setInfo; + AttachToNewResource(index); + } } void ClearByCpuHandle(SIZE_T cpuHandle) const @@ -168,6 +173,7 @@ typedef struct HeapInfo { LOG_TRACK("Resource: {:X}, Res: {}x{}, Format: {}", (size_t) info[index].buffer, info[index].width, info[index].height, (UINT) info[index].format); + DetachFromOldResource(index); } @@ -186,6 +192,7 @@ typedef struct HeapInfo { LOG_TRACK("Resource: {:X}, Res: {}x{}, Format: {}", (size_t) info[index].buffer, info[index].width, info[index].height, (UINT) info[index].format); + DetachFromOldResource(index); } diff --git a/OptiScaler/upscalers/dlss/DLSSFeature.cpp b/OptiScaler/upscalers/dlss/DLSSFeature.cpp index 08baadbe..5a9eb225 100644 --- a/OptiScaler/upscalers/dlss/DLSSFeature.cpp +++ b/OptiScaler/upscalers/dlss/DLSSFeature.cpp @@ -12,7 +12,7 @@ void DLSSFeature::ProcessEvaluateParams(NVSDK_NGX_Parameter* InParameters) // override sharpness if (Config::Instance()->OverrideSharpness.value_or_default() && - !(State::Instance().swapchainApi != Vulkan && Config::Instance()->RcasEnabled.value_or_default())) + !(State::Instance().api != Vulkan && Config::Instance()->RcasEnabled.value_or_default())) { auto sharpness = Config::Instance()->Sharpness.value_or_default(); @@ -65,8 +65,7 @@ void DLSSFeature::ProcessInitParams(NVSDK_NGX_Parameter* InParameters) InParameters->Set(NVSDK_NGX_Parameter_DLSS_Feature_Create_Flags, featureFlags); // Resolution ----------------------------- - if (State::Instance().swapchainApi != Vulkan && Config::Instance()->OutputScalingEnabled.value_or_default() && - LowResMV()) + if (State::Instance().api != Vulkan && Config::Instance()->OutputScalingEnabled.value_or_default() && LowResMV()) { LOG_DEBUG("Output Scaling is active"); diff --git a/OptiScaler/upscalers/dlssd/DLSSDFeature.cpp b/OptiScaler/upscalers/dlssd/DLSSDFeature.cpp index cc2eec57..117e0336 100644 --- a/OptiScaler/upscalers/dlssd/DLSSDFeature.cpp +++ b/OptiScaler/upscalers/dlssd/DLSSDFeature.cpp @@ -12,7 +12,7 @@ void DLSSDFeature::ProcessEvaluateParams(NVSDK_NGX_Parameter* InParameters) // override sharpness if (Config::Instance()->OverrideSharpness.value_or_default() && - !(State::Instance().swapchainApi == DX12 && Config::Instance()->RcasEnabled.value_or_default())) + !(State::Instance().api == DX12 && Config::Instance()->RcasEnabled.value_or_default())) { auto sharpness = Config::Instance()->Sharpness.value_or_default(); @@ -61,8 +61,7 @@ void DLSSDFeature::ProcessInitParams(NVSDK_NGX_Parameter* InParameters) InParameters->Set(NVSDK_NGX_Parameter_DLSS_Feature_Create_Flags, featureFlags); // Resolution ----------------------------- - if (State::Instance().swapchainApi != Vulkan && Config::Instance()->OutputScalingEnabled.value_or_default() && - LowResMV()) + if (State::Instance().api != Vulkan && Config::Instance()->OutputScalingEnabled.value_or_default() && LowResMV()) { float ssMulti = Config::Instance()->OutputScalingMultiplier.value_or_default();