diff --git a/OptiScaler.ini b/OptiScaler.ini index 75b72b28..2af8903b 100644 --- a/OptiScaler.ini +++ b/OptiScaler.ini @@ -934,6 +934,10 @@ LatencyFlexMode=auto ; Default (auto) is 0 ForceReflex=auto +; When using FG via Nvngx, sets the FPS target for dynamic multi frame generation +; Default (auto) is 0 +FramerateTargetDMFG=auto + ; ------------------------------------------------------- [NvApi] diff --git a/OptiScaler/Config.cpp b/OptiScaler/Config.cpp index 28d614e2..81260a11 100644 --- a/OptiScaler/Config.cpp +++ b/OptiScaler/Config.cpp @@ -648,6 +648,12 @@ bool Config::Reload(std::filesystem::path iniPath) FN_ForceReflex.set_from_config(*v); else FN_ForceReflex.reset(); + + FramerateTargetDMFG.set_from_config(readInt("fakenvapi", "FramerateTargetDMFG")); + + // DMFG is a mess with our reflex implementations, disable by default + if (FramerateTargetDMFG.value_or_default() != 0 && !FN_ForceReflex.has_value()) + FN_ForceReflex.set_volatile_value(ForceReflex::ForceDisable); } // Inputs @@ -1357,6 +1363,8 @@ bool Config::SaveIni() ini.SetValue("fakenvapi", "LatencyFlexMode", GetIntValue(Instance()->FN_LatencyFlexMode.value_for_config()).c_str()); ini.SetValue("fakenvapi", "ForceReflex", GetIntValue(Instance()->FN_ForceReflex.value_for_config()).c_str()); + ini.SetValue("fakenvapi", "FramerateTargetDMFG", + GetIntValue(Instance()->FramerateTargetDMFG.value_for_config()).c_str()); } // inputs diff --git a/OptiScaler/Config.h b/OptiScaler/Config.h index 7f85eea5..1c917e69 100644 --- a/OptiScaler/Config.h +++ b/OptiScaler/Config.h @@ -529,6 +529,7 @@ class Config CustomOptional FN_ForceLatencyFlex { false }; CustomOptional FN_LatencyFlexMode { LFXMode::Conservative }; CustomOptional FN_ForceReflex { ForceReflex::InGame }; + CustomOptional FramerateTargetDMFG { 0 }; // Inputs CustomOptional EnableDlssInputs { true }; diff --git a/OptiScaler/framegen/nvngx/Nvngx_FG.cpp b/OptiScaler/framegen/nvngx/Nvngx_FG.cpp index 3cea9c4e..40a64ea9 100644 --- a/OptiScaler/framegen/nvngx/Nvngx_FG.cpp +++ b/OptiScaler/framegen/nvngx/Nvngx_FG.cpp @@ -57,7 +57,7 @@ void Nvngx_FG::setSetting(const wchar_t* setting, const wchar_t* value) HMODULE Nvngx_FG::TryInitMFG() { - auto dllPath = Util::DllPath().parent_path() / "fsr3fg_mfg.asi"; + auto dllPath = Util::DllPath().parent_path() / "dlss-enabler-headless.asi"; // set early so the hooks know _mfg = true; @@ -419,6 +419,13 @@ NVSDK_NGX_Result Nvngx_FG::D3D12_EvaluateFeature(ID3D12GraphicsCommandList* InCm } } + if (Config::Instance()->FramerateTargetDMFG.value_or_default() != 0 && fakenvapi::isUsingAsMainNvapi()) + { + int frameCount = 0; + InParameters->Get("DLSSG.MultiFrameCount", &frameCount); + Config::Instance()->FGDLSSGOverrideInterpolationCount.set_volatile_value(frameCount); + } + NVSDK_NGX_Handle TempHandle = { .Id = InFeatureHandle->Id - DLSSG_MOD_ID_OFFSET }; return _DLSSG_D3D12_EvaluateFeature(InCmdList, &TempHandle, InParameters, InCallback); } diff --git a/OptiScaler/menu/menu_common.cpp b/OptiScaler/menu/menu_common.cpp index d3174f35..e13bc55a 100644 --- a/OptiScaler/menu/menu_common.cpp +++ b/OptiScaler/menu/menu_common.cpp @@ -1431,7 +1431,7 @@ bool MenuCommon::RenderMenu() { refreshRate = Util::GetActiveRefreshRate(_handle); - auto dllPath = Util::DllPath().parent_path() / "fsr3fg_mfg.asi"; + auto dllPath = Util::DllPath().parent_path() / "dlss-enabler-headless.asi"; state.NukemsFilesAvailable = gExists.Get(dllPath); if (!state.NukemsFilesAvailable) @@ -4167,7 +4167,7 @@ bool MenuCommon::RenderMenu() if (Nvngx_FG::isMFG()) { - ImGui::Text("Using Nukem's via the MFG mod from fsr3fg_mfg.asi"); + ImGui::Text("Using Nukem's via the MFG mod from dlss-enabler-headless.asi"); } if (!ReflexHooks::isReflexHooked()) diff --git a/OptiScaler/nvapi/fakenvapi.cpp b/OptiScaler/nvapi/fakenvapi.cpp index 6804a150..bed17236 100644 --- a/OptiScaler/nvapi/fakenvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi.cpp @@ -163,6 +163,7 @@ void* __cdecl fakenvapi::queryInterface(NvU32 id) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetSetting) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SetSetting) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_DestroySession) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_NGX_GetDriverFeatureSupport) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unknown_1) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_1) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_2) diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp index e73cab8f..47722bed 100644 --- a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp +++ b/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp @@ -43,7 +43,8 @@ bool LowLatency::update_low_latency_tech(IUnknown* pDevice) } if (!Config::Instance()->FN_ForceLatencyFlex.value_or_default() && - (!Nvngx_FG::isMFG() || ReflexHooks::dlssgFrameCountToGenerate() <= 1)) + (!Nvngx_FG::isMFG() || ReflexHooks::dlssgFrameCountToGenerate() <= 1) && + Config::Instance()->FramerateTargetDMFG.value_or_default() == 0) { currently_active_tech = new AntiLag2(); if (currently_active_tech->init(pDevice)) @@ -82,7 +83,7 @@ bool LowLatency::update_low_latency_tech(IUnknown* pDevice) bool change_detected = last_force_latencyflex != force_latencyflex; last_force_latencyflex = force_latencyflex; - if (State::Instance().fakenvapiReloadLowLatency) + if (State::Instance().fakenvapiReloadLowLatency && Config::Instance()->FramerateTargetDMFG.value_or_default() == 0) { change_detected = true; State::Instance().fakenvapiReloadLowLatency = false; diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp index 0772c258..305e6f22 100644 --- a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp +++ b/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp @@ -43,7 +43,7 @@ bool LowLatency::update_low_latency_tech(HANDLE vkDevice) bool change_detected = last_force_latencyflex != force_latencyflex; last_force_latencyflex = force_latencyflex; - if (State::Instance().fakenvapiReloadLowLatency) + if (State::Instance().fakenvapiReloadLowLatency && Config::Instance()->FramerateTargetDMFG.value_or_default() == 0) { change_detected = true; State::Instance().fakenvapiReloadLowLatency = false; diff --git a/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp b/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp index f97ee012..993ed77b 100644 --- a/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp @@ -2,6 +2,7 @@ #include "nvapi_calls.h" #include "proxies/Dxgi_Proxy.h" #include +#include using Microsoft::WRL::ComPtr; @@ -723,19 +724,58 @@ NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSP NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { - LOG_DEBUG("Missing get setting: {}", settingId); + auto setting = (ESetting) settingId; + + auto dmfgFpsTarget = Config::Instance()->FramerateTargetDMFG.value_or_default(); + if (setting == NGX_DLSSG_MODE_ID && dmfgFpsTarget != 0) + { + pSetting->settingId = settingId; + constexpr auto name = L"NGX_DLSSG_MODE_ID"; + memcpy_s(pSetting->settingName, sizeof(pSetting->settingName), name, sizeof(*name) * wcslen(name)); + pSetting->settingType = NVDRS_DWORD_TYPE; + pSetting->u32CurrentValue = NGX_DLSSG_MODE_DYNAMIC; + + LOG_DEBUG("Set NGX_DLSSG_MODE_ID"); + + return OK(); + } + + if (setting == NGX_DLSSG_DYNAMIC_TARGET_FRAME_RATE_ID && dmfgFpsTarget != 0) + { + pSetting->settingId = settingId; + constexpr auto name = L"NGX_DLSSG_DYNAMIC_TARGET_FRAME_RATE_ID"; + memcpy_s(pSetting->settingName, sizeof(pSetting->settingName), name, sizeof(*name) * wcslen(name)); + pSetting->settingType = NVDRS_DWORD_TYPE; + pSetting->u32CurrentValue = dmfgFpsTarget; + + LOG_DEBUG("Set NGX_DLSSG_DYNAMIC_TARGET_FRAME_RATE_ID to {}", pSetting->u32CurrentValue); + + return OK(); + } + + LOG_DEBUG("Missing get setting: {:X}", settingId); return OK(); } NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING* pSetting) { - LOG_DEBUG("Missing set setting: {}", pSetting->settingId); + LOG_DEBUG("Missing set setting: 0x{:X}", pSetting->settingId); return OK(); } NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { return OK(); } +NvAPI_Status __cdecl NvAPI_NGX_GetDriverFeatureSupport(NV_NGX_GET_DRIVER_FEATURE_SUPPORT_PARAMS* pParams) +{ + for (size_t i = 0; i < pParams->featureCount; i++) + { + if (pParams->featureSupportInfo[i].featureId == NV_NGX_DRIVER_FEATURE_ID_SET_FLIP_CONFIG_V2) + pParams->featureSupportInfo[i].bSupported = NV_TRUE; + } + return OK(); +} + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { std::fill(pMiscUnk, pMiscUnk + 4, 0x1); diff --git a/OptiScaler/nvapi/fakenvapi/nvapi_calls.h b/OptiScaler/nvapi/fakenvapi/nvapi_calls.h index 237d08c6..637ac220 100644 --- a/OptiScaler/nvapi/fakenvapi/nvapi_calls.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi_calls.h @@ -110,6 +110,7 @@ NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProf NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING* pSetting); NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session); +NvAPI_Status __cdecl NvAPI_NGX_GetDriverFeatureSupport(NV_NGX_GET_DRIVER_FEATURE_SUPPORT_PARAMS* pParams); NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk); NvAPI_Status __cdecl NvAPI_SK_1(IUnknown* unknown); NvAPI_Status __cdecl NvAPI_SK_2(IUnknown* unknown);