From 5dfedd68365cb1f6fa96b769671bfefd287a7086 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 23 Oct 2026 02:01:18 +0200 Subject: [PATCH] Lobotomize fakenvapi Alternative titles: complete the move of low latency code out of fakenvapi --- OptiScaler/OptiScaler.vcxproj | 4 - OptiScaler/OptiScaler.vcxproj.filters | 12 - OptiScaler/State.h | 1 - OptiScaler/hooks/Reflex_Hooks.cpp | 55 +-- OptiScaler/low_latency/input/input_common.cpp | 28 +- OptiScaler/low_latency/input/input_common.h | 8 +- OptiScaler/low_latency/input/input_reflex.cpp | 4 +- .../low_latency_tech/ll_reflex.cpp | 4 +- OptiScaler/menu/menu_common.cpp | 76 +--- OptiScaler/nvapi/NvApiHooks.cpp | 10 - OptiScaler/nvapi/fakenvapi.cpp | 73 ---- OptiScaler/nvapi/fakenvapi.h | 12 - OptiScaler/nvapi/fakenvapi/low_latency.cpp | 79 ----- OptiScaler/nvapi/fakenvapi/low_latency.h | 80 ----- .../nvapi/fakenvapi/low_latency_d3d.cpp | 327 ------------------ OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp | 238 ------------- OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp | 152 +------- OptiScaler/nvapi/fakenvapi/nvapi_calls.h | 20 -- 18 files changed, 47 insertions(+), 1136 deletions(-) delete mode 100644 OptiScaler/nvapi/fakenvapi/low_latency.cpp delete mode 100644 OptiScaler/nvapi/fakenvapi/low_latency.h delete mode 100644 OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp delete mode 100644 OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index b350356d..8dfeda69 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -270,7 +270,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y - @@ -618,8 +617,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y - - @@ -627,7 +624,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y - diff --git a/OptiScaler/OptiScaler.vcxproj.filters b/OptiScaler/OptiScaler.vcxproj.filters index 9ee36ec7..aeb98ce6 100644 --- a/OptiScaler/OptiScaler.vcxproj.filters +++ b/OptiScaler/OptiScaler.vcxproj.filters @@ -806,9 +806,6 @@ Header Files - - Header Files - Header Files @@ -1604,12 +1601,6 @@ Source Files - - Source Files - - - Source Files - Source Files @@ -1631,9 +1622,6 @@ Source Files - - Source Files - Source Files diff --git a/OptiScaler/State.h b/OptiScaler/State.h index deb6ebd8..5fda0959 100644 --- a/OptiScaler/State.h +++ b/OptiScaler/State.h @@ -278,7 +278,6 @@ class State bool reflexLimitsFps = false; bool reflexShowWarning = false; bool rtssReflexInjection = false; - bool fakenvapiReloadLowLatency = false; UINT64 reflexFrameId = 0; UINT64 frameCount = 0; bool vkAntiLagSupported = false; diff --git a/OptiScaler/hooks/Reflex_Hooks.cpp b/OptiScaler/hooks/Reflex_Hooks.cpp index 64d5271d..6125fc89 100644 --- a/OptiScaler/hooks/Reflex_Hooks.cpp +++ b/OptiScaler/hooks/Reflex_Hooks.cpp @@ -2,8 +2,6 @@ #include "Reflex_Hooks.h" #include -#include - #include #include @@ -537,8 +535,7 @@ void ReflexHooks::update(bool fgActive, bool isVulkan) if (isVulkan && _lastVkSleepDev) { // fgActive doesn't matter for vulkan - // isUsingAsMainNvapi() because fakenvapi might override the reflex' setting and we don't know it - State::Instance().reflexLimitsFps = fakenvapi::isUsingAsMainNvapi() || _lastVkSleepParams.bLowLatencyMode; + State::Instance().reflexLimitsFps = _lastVkSleepParams.bLowLatencyMode; } else if (!reflexOutput) { @@ -548,33 +545,17 @@ void ReflexHooks::update(bool fgActive, bool isVulkan) else if (_lastSleepDev) { // Don't use when: Real Reflex markers + FSR FG + Reflex disabled, causes huge input latency - State::Instance().reflexLimitsFps = - fakenvapi::isUsingAsMainNvapi() || !fgActive || _lastSleepParams.bLowLatencyMode; - State::Instance().reflexShowWarning = State::Instance().activeFgOutput == FGOutput::FSRFG && - !fakenvapi::isUsingAsMainNvapi() && fgActive && - _lastSleepParams.bLowLatencyMode; + State::Instance().reflexLimitsFps = !fgActive || _lastSleepParams.bLowLatencyMode; + State::Instance().reflexShowWarning = + State::Instance().activeFgOutput == FGOutput::FSRFG && fgActive && _lastSleepParams.bLowLatencyMode; } else { State::Instance().reflexLimitsFps = false; } - // Disable reflex fps limiting when reflex is force disabled - // TODO: It changes without pressing apply, XeLL with XeFG can't actually be disabled so this is wrong - // - // Wait for fakenvapi to be merged into Opti for better integration - // - // if (State::Instance().reflexLimitsFps && (fakenvapi::isUsingAsMainNvapi() || - // fakenvapi::isUsingOnNvidia()) - // && - // Config::Instance()->FN_ForceReflex.value_or_default() == 1) - //{ - // State::Instance().reflexLimitsFps = false; - //} - static float lastFps = 0; static bool lastReflexLimitsFps = State::Instance().reflexLimitsFps; - static LowLatencyMode lastLowLatencyMode = fakenvapi::getCurrentMode(); // Reset required when toggling Reflex if (State::Instance().reflexLimitsFps != lastReflexLimitsFps) @@ -583,12 +564,6 @@ void ReflexHooks::update(bool fgActive, bool isVulkan) lastFps = 0; setFPSLimit(0); } - else if (fakenvapi::isUsingAsMainNvapi() && lastLowLatencyMode != fakenvapi::getCurrentMode()) - { - lastLowLatencyMode = fakenvapi::getCurrentMode(); - lastFps = 0; - setFPSLimit(0); - } if (!State::Instance().reflexLimitsFps) return; @@ -599,23 +574,6 @@ void ReflexHooks::update(bool fgActive, bool isVulkan) if (lastFgNumFramesToGenerate != _FgNumFramesToGenerate) { - if (fakenvapi::isUsingAsMainNvapi()) - { - // Don't reload when using Dynamic MFG - if (State::Instance().dlssgLastSetMode != sl::DLSSGMode::eDynamic && - !Config::Instance()->FGDLSSGForceDMFG.value_or_default()) - { - State::Instance().fakenvapiReloadLowLatency = true; - } - - // fakenvapi's latency techs fall apart with Dynamic MFG - if (Config::Instance()->FN_ForceReflex.value_or_default() != ForceReflex::ForceEnable && - State::Instance().dlssgLastSetMode == sl::DLSSGMode::eDynamic) - { - Config::Instance()->FN_ForceReflex.set_volatile_value(ForceReflex::ForceDisable); - } - } - lastFgNumFramesToGenerate = _FgNumFramesToGenerate; setFPSLimit(currentFps); @@ -635,11 +593,6 @@ void ReflexHooks::update(bool fgActive, bool isVulkan) if (!driverCountsFg) currentFps /= 2; } - else if (_FgNumFramesToGenerate > 0 && fakenvapi::isUsingAsMainNvapi() && - fakenvapi::getCurrentMode() != LowLatencyMode::XeLL) - { - currentFps /= (_FgNumFramesToGenerate + 1); - } if (currentFps != lastFps) { diff --git a/OptiScaler/low_latency/input/input_common.cpp b/OptiScaler/low_latency/input/input_common.cpp index ad6a94c4..07f8d4d7 100644 --- a/OptiScaler/low_latency/input/input_common.cpp +++ b/OptiScaler/low_latency/input/input_common.cpp @@ -145,7 +145,7 @@ LowLatencyMode InputCommon::default_output(API api) if (vendorId == VendorId::AMD && VulkanHooks::o_vkAntiLagUpdateAMD != nullptr) return LowLatencyMode::AntiLagVk; - if (vendorId == VendorId::Nvidia && VulkanHooks::o_vkSetLatencySleepModeNV != nullptr) + if (driver_reflex_available(api)) return LowLatencyMode::Reflex; return LowLatencyMode::LatencyFlex; @@ -158,7 +158,7 @@ LowLatencyMode InputCommon::default_output(API api) if (vendorId == VendorId::AMD) return LowLatencyMode::AntiLag2; - if (vendorId == VendorId::Nvidia && !fakenvapi::isUsingAsMainNvapi()) + if (driver_reflex_available(api)) return LowLatencyMode::Reflex; return LowLatencyMode::LatencyFlex; @@ -166,21 +166,29 @@ LowLatencyMode InputCommon::default_output(API api) const char* InputCommon::output_unavailable(LowLatencyMode output, API api) { - auto vendorId = IdentifyGpu::getPrimaryGpu().vendorId; + if (output == LowLatencyMode::Reflex && !driver_reflex_available(api)) + return api == API::Vulkan ? "Needs an Nvidia GPU with VK_NV_low_latency2" : "Needs an Nvidia GPU"; - // On D3D the driver's Reflex is reached through nvapi, fakenvapi's is a translation of its own - if (output == LowLatencyMode::Reflex && - (vendorId != VendorId::Nvidia || (api != API::Vulkan && fakenvapi::isUsingAsMainNvapi()))) - { - return "Needs an Nvidia GPU"; - } + if (output == LowLatencyMode::AntiLagVk && VulkanHooks::o_vkAntiLagUpdateAMD == nullptr) + return "Needs an AMD GPU with VK_AMD_anti_lag"; - if ((output == LowLatencyMode::AntiLag2 || output == LowLatencyMode::AntiLagVk) && vendorId != VendorId::AMD) + if (output == LowLatencyMode::AntiLag2 && IdentifyGpu::getPrimaryGpu().vendorId != VendorId::AMD) return "Needs an AMD GPU"; return nullptr; } +bool InputCommon::driver_reflex_available(API api) +{ + if (IdentifyGpu::getPrimaryGpu().vendorId != VendorId::Nvidia) + return false; + + if (api == API::Vulkan) + return VulkanHooks::o_vkSetLatencySleepModeNV != nullptr; + + return !fakenvapi::isUsingAsMainNvapi(); +} + LowLatencyMode InputCommon::for_api(LowLatencyMode mode, API api) { if (api == API::Vulkan && mode == LowLatencyMode::AntiLag2) diff --git a/OptiScaler/low_latency/input/input_common.h b/OptiScaler/low_latency/input/input_common.h index 72572b49..6b9fcd6c 100644 --- a/OptiScaler/low_latency/input/input_common.h +++ b/OptiScaler/low_latency/input/input_common.h @@ -193,10 +193,14 @@ class InputCommon // The GPU vendor's own low latency output static LowLatencyMode default_output(API api); - // Why the GPU can't run the output, nullptr when it can: Reflex needs an Nvidia GPU (and its nvapi on D3D), - // AntiLag 2 an AMD GPU + // Why the GPU can't run the output, nullptr when it can: Reflex needs the driver's Reflex, AntiLag an AMD GPU + // (and VK_AMD_anti_lag on Vulkan) static const char* output_unavailable(LowLatencyMode output, API api); + // The driver's Reflex: an Nvidia GPU with its nvapi on D3D (fakenvapi's isn't Reflex), with VK_NV_low_latency2 + // on Vulkan + static bool driver_reflex_available(API api); + // Why the input can't drive the output, nullptr when it can static const char* incompatibility(LowLatencyInput input, LowLatencyMode output); diff --git a/OptiScaler/low_latency/input/input_reflex.cpp b/OptiScaler/low_latency/input/input_reflex.cpp index b6138c99..bcc4c84f 100644 --- a/OptiScaler/low_latency/input/input_reflex.cpp +++ b/OptiScaler/low_latency/input/input_reflex.cpp @@ -23,7 +23,7 @@ static bool FromOptiScaler(void* returnAddress) // With NVIDIA's nvapi OptiScaler's Streamline reaches the driver, with fakenvapi it's the OptiScaler input template static Fn ToDriver(unsigned int id) { - if (fakenvapi::isUsingAsMainNvapi()) + if (!InputCommon::driver_reflex_available(API::DX12)) return nullptr; return reinterpret_cast(ReflexHooks::getHookedReflex(id)); @@ -79,7 +79,7 @@ NvAPI_Status InputReflex::D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STA bool own = FromOptiScaler(_ReturnAddress()); - if (own && !fakenvapi::isUsingAsMainNvapi() && NvApiHooks::o_NvAPI_QueryInterface != nullptr) + if (own && InputCommon::driver_reflex_available(API::DX12) && NvApiHooks::o_NvAPI_QueryInterface != nullptr) { if (auto driver = GET_INTERFACE(NvAPI_D3D_GetSleepStatus, NvApiHooks::o_NvAPI_QueryInterface)) return driver(pDevice, pGetSleepStatusParams); diff --git a/OptiScaler/low_latency/low_latency_tech/ll_reflex.cpp b/OptiScaler/low_latency/low_latency_tech/ll_reflex.cpp index b06bae10..c88b187c 100644 --- a/OptiScaler/low_latency/low_latency_tech/ll_reflex.cpp +++ b/OptiScaler/low_latency/low_latency_tech/ll_reflex.cpp @@ -3,6 +3,7 @@ #include #include +#include bool Reflex::init(IUnknown* pDevice) { @@ -12,8 +13,7 @@ bool Reflex::init(IUnknown* pDevice) if (NvApiHooks::o_NvAPI_QueryInterface == nullptr) LibraryLoadHooks::LoadNvApi(); - // fakenvapi's Reflex is a translation of its own, only the driver's is Reflex - if (NvApiHooks::o_NvAPI_QueryInterface == nullptr || fakenvapi::isUsingAsMainNvapi()) + if (NvApiHooks::o_NvAPI_QueryInterface == nullptr || !InputCommon::driver_reflex_available(API::DX12)) { LOG_INFO("Reflex needs NVIDIA's nvapi"); return false; diff --git a/OptiScaler/menu/menu_common.cpp b/OptiScaler/menu/menu_common.cpp index 4af1083d..0c34cd72 100644 --- a/OptiScaler/menu/menu_common.cpp +++ b/OptiScaler/menu/menu_common.cpp @@ -5864,57 +5864,27 @@ void MenuCommon::RenderFramerateSettings(RenderMenuContext& ctx) "Framerate", "Uses Reflex when possible\nOn AMD/Intel cards, you can use Fakenvapi to substitute Reflex"); static std::string currentMethod {}; - LowLatencyMode fakenvapiMode = {}; + const LowLatencyMode activeOutput = InputCommon::active_output(); + + // The Reflex output limits through the driver's Reflex if (state.reflexLimitsFps) { - fakenvapiMode = fakenvapi::getCurrentMode(); - - // The D3D Reflex output limits through the driver's Reflex, fakenvapi's mode is only its own - LowLatencyInput activeInput {}; - LowLatencyMode activeOutput {}; - InputCommon::get_currently_active(activeInput, activeOutput); - - if (activeOutput == LowLatencyMode::Reflex) - fakenvapiMode = LowLatencyMode::None; - - if (fakenvapiMode == LowLatencyMode::AntiLag2) - currentMethod = "FSR Anti-Lag 2.0"; - else if (fakenvapiMode == LowLatencyMode::LatencyFlex) - currentMethod = "LatencyFlex"; - else if (fakenvapiMode == LowLatencyMode::XeLL) - currentMethod = "XeLL"; - else if (fakenvapiMode == LowLatencyMode::AntiLagVk) - currentMethod = "Vulkan AntiLag"; - else if (fakenvapiMode == LowLatencyMode::None) - { - if (fakenvapi::isUsingAsMainNvapi()) - currentMethod = "None"; - else - currentMethod = "Reflex"; - } - - if (state.rtssReflexInjection && fakenvapiMode == LowLatencyMode::AntiLag2 && - config->FGOutput.value_or_default() == FGOutput::FSRFG) - ImGui::TextColored(toneMapColor(ImVec4(1.f, 0.8f, 0.f, 1.f)), - "Using RTSS Reflex injection with FSR Anti-Lag 2.0 and FSR FG " - "might cause issues"); + currentMethod = "Reflex"; } else if (InputCommon::can_limit_fps()) { - fakenvapiMode = InputCommon::active_output(); - // The game's XeFG with its own XeLL if (InputXeLL::IsNative()) currentMethod = "Game's XeLL"; - else if (fakenvapiMode == LowLatencyMode::AntiLag2) + else if (activeOutput == LowLatencyMode::AntiLag2) currentMethod = "FSR Anti-Lag 2.0"; - else if (fakenvapiMode == LowLatencyMode::LatencyFlex) + else if (activeOutput == LowLatencyMode::LatencyFlex) currentMethod = "LatencyFlex"; - else if (fakenvapiMode == LowLatencyMode::AntiLagVk) + else if (activeOutput == LowLatencyMode::AntiLagVk) currentMethod = "Vulkan AntiLag"; - else if (fakenvapiMode == LowLatencyMode::Reflex) + else if (activeOutput == LowLatencyMode::Reflex) currentMethod = "Reflex"; - else if (fakenvapiMode == LowLatencyMode::FpsLimiter) + else if (activeOutput == LowLatencyMode::FpsLimiter) currentMethod = "FPS Limiter"; else currentMethod = "XeLL"; @@ -5927,15 +5897,9 @@ void MenuCommon::RenderFramerateSettings(RenderMenuContext& ctx) if (state.rtssReflexInjection) currentMethod.append(" (RTSS)"); - const bool fakenvapiInactive = (fakenvapi::isUsingAsMainNvapi() || fakenvapiMode == LowLatencyMode::XeLL) && - !fakenvapi::isLowLatencyActive() && state.reflexLimitsFps; - - if (fakenvapiInactive) - currentMethod.append(" (inactive)"); - ImGui::Text("Current method: %s", currentMethod.c_str()); - if (fakenvapiMode == LowLatencyMode::AntiLag2) + if (activeOutput == LowLatencyMode::AntiLag2) ShowTooltip("FSR Anti-Lag 2.0 is the new name for AntiLag 2\nDon't ask me why"); if (state.reflexShowWarning) @@ -5978,7 +5942,7 @@ void MenuCommon::RenderFramerateSettings(RenderMenuContext& ctx) float refreshRateF = static_cast(refreshRate); // it's fine to use with real reflex, we only care about antilag - auto fpsLimitTech = fakenvapi::getCurrentMode(); + auto fpsLimitTech = InputCommon::active_output(); constexpr float margin = 0.3f; // in ms float frameCap = std::round(10000.f / (1000.f / refreshRateF + margin)) / 10.f; @@ -6109,8 +6073,6 @@ void MenuCommon::RenderLowLatencySettings(RenderMenuContext& ctx) const auto api = InputCommon::uses_api(); const bool vulkan = api == API::Vulkan; const bool outputForced = InputCommon::forced_output().has_value(); - const auto vendorId = IdentifyGpu::getPrimaryGpu().vendorId; - const bool nvidia = vendorId == VendorId::Nvidia; // OptiScaler's XeFG paces with XeLL on D3D12 (also for D3D11 games through interop), the GPU's Reflex or // AntiLag 2 output can sleep instead while XeFG keeps an XeLL context of its own @@ -6127,22 +6089,12 @@ void MenuCommon::RenderLowLatencySettings(RenderMenuContext& ctx) option.tooltip = condition ? reason : ""; }; - disable(lowLatencyOutput[(uint32_t) LowLatencyMode::AntiLagVk], VulkanHooks::o_vkAntiLagUpdateAMD == nullptr, - "Needs an AMD GPU with VK_AMD_anti_lag"); - - if (vulkan) + for (auto mode : { LowLatencyMode::Reflex, LowLatencyMode::AntiLag2, LowLatencyMode::AntiLagVk }) { - disable(lowLatencyOutput[(uint32_t) LowLatencyMode::Reflex], - !nvidia || VulkanHooks::o_vkSetLatencySleepModeNV == nullptr, - "Needs an Nvidia GPU with VK_NV_low_latency2"); - } - else - { - disable(lowLatencyOutput[(uint32_t) LowLatencyMode::Reflex], !nvidia || fakenvapi::isUsingAsMainNvapi(), - "Needs an Nvidia GPU"); + auto reason = InputCommon::output_unavailable(mode, api); + disable(lowLatencyOutput[(uint32_t) mode], reason != nullptr, reason); } - disable(lowLatencyOutput[(uint32_t) LowLatencyMode::AntiLag2], vendorId != VendorId::AMD, "Needs an AMD GPU"); disable(lowLatencyOutput[(uint32_t) LowLatencyMode::LatencyFlex], optiXefg, "Not with XeFG"); lowLatencyOutput[(uint32_t) LowLatencyMode::Auto].label = "Auto"; diff --git a/OptiScaler/nvapi/NvApiHooks.cpp b/OptiScaler/nvapi/NvApiHooks.cpp index ecc7f372..746c8a52 100644 --- a/OptiScaler/nvapi/NvApiHooks.cpp +++ b/OptiScaler/nvapi/NvApiHooks.cpp @@ -263,10 +263,6 @@ void* __stdcall NvApiHooks::hkNvAPI_QueryInterface(unsigned int InterfaceId) return InputReflex::Vulkan_SetLatencyMarker; else if (InterfaceId == GET_ID(NvAPI_Vulkan_NotifyOutOfBandVkQueue)) return InputReflex::Vulkan_NotifyOutOfBandVkQueue; - - // LOG_DEBUG("counter: {}, hookReflex()", qiCounter); - ReflexHooks::hookReflex(o_NvAPI_QueryInterface); - return ReflexHooks::getHookedReflex(InterfaceId); } ReflexHooks::hookReflex(o_NvAPI_QueryInterface); @@ -315,12 +311,6 @@ void NvApiHooks::Hook(HMODULE nvapiModule) { LOG_INFO("NvAPI_QueryInterface found, hooking!"); - constexpr bool leanMode = true; - if (fakenvapi::isUsingAsMainNvapi()) - fakenvapi::init(!leanMode); - else if (State::Instance().activeFgOutput == FGOutput::XeFG) - fakenvapi::init(leanMode); - DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&) o_NvAPI_QueryInterface, hkNvAPI_QueryInterface); diff --git a/OptiScaler/nvapi/fakenvapi.cpp b/OptiScaler/nvapi/fakenvapi.cpp index f05c1df2..a5b85831 100644 --- a/OptiScaler/nvapi/fakenvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi.cpp @@ -12,20 +12,6 @@ std::unordered_map fakenvapi::idToFuncMapping; -void fakenvapi::init(bool onlyContext) -{ - LowLatencyCtx::init(); - - if (onlyContext) - return; -} - -void fakenvapi::deinit() -{ - LowLatencyCtx::get()->deinit_current_tech(); - LowLatencyCtx::shutdown(); -} - // names from: https://github.com/SveSop/nvapi_standalone/blob/master/dlls/nvapi/nvapi.c static NVAPI_INTERFACE_TABLE additional_interface_table[] = { { "NvAPI_Diag_ReportCallStart", 0x33c7358c }, { "NvAPI_Diag_ReportCallReturn", 0x593e8644 }, @@ -102,11 +88,6 @@ void* __cdecl fakenvapi::queryInterface(NvU32 id) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SYS_GetGpuAndOutputIdFromDisplayId) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetResourceHint) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetObjectHandleForResource) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetSleepStatus) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetLatency) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetSleepMode) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetLatencyMarker) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_Sleep) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetReflexSync) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_IsNvShaderExtnOpCodeSupported) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_BeginUAVOverlap) @@ -118,14 +99,6 @@ void* __cdecl fakenvapi::queryInterface(NvU32 id) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_BuildRaytracingAccelerationStructureEx) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_NotifyOutOfBandCommandQueue) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_SetAsyncFrameMarker) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_InitLowLatencyDevice) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_DestroyLowLatencyDevice) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_GetSleepStatus) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_SetSleepMode) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_Sleep) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_GetLatency) - INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_SetLatencyMarker) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_NotifyOutOfBandVkQueue) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_CreateSession) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_LoadSettings) @@ -148,52 +121,6 @@ void* __cdecl fakenvapi::queryInterface(NvU32 id) // return registry.insert({ id, nullptr }).first->second; } -bool fakenvapi::updateModeAndContext() -{ - LOG_FUNC(); - - auto lowLatencyCtx = LowLatencyCtx::get(); - - if (!lowLatencyCtx) - { - // Real reflex should fall here and not log - if (_usingFakenvapiAsMainNvapi) - LOG_ERROR("Couldn't get low latency context"); - - return false; - } - - auto result = lowLatencyCtx->get_low_latency_tech_context(&_lowLatencyTechContext, &_lowLatencyMode); - - if (!result) - LOG_TRACE_FAKENVAPI("Can't get Low Latency context from fakenvapi"); - - return result; -} - -bool fakenvapi::isLowLatencyActive() -{ - auto lowLatencyCtx = LowLatencyCtx::get(); - - if (!lowLatencyCtx) - { - if (_usingFakenvapiAsMainNvapi) - LOG_ERROR("Couldn't get low latency context"); - - return false; - } - - return lowLatencyCtx->is_low_latency_enabled(); -} - -LowLatencyMode fakenvapi::getCurrentMode() -{ - if (updateModeAndContext()) - return _lowLatencyMode; - else - return LowLatencyMode::None; -} - bool fakenvapi::isUsingAsMainNvapi() { return _usingFakenvapiAsMainNvapi; } void fakenvapi::setUsingAsMainNvapi(bool usingAsMain) { _usingFakenvapiAsMainNvapi = usingAsMain; } diff --git a/OptiScaler/nvapi/fakenvapi.h b/OptiScaler/nvapi/fakenvapi.h index ca2b7dfb..57457c1c 100644 --- a/OptiScaler/nvapi/fakenvapi.h +++ b/OptiScaler/nvapi/fakenvapi.h @@ -8,15 +8,9 @@ class fakenvapi { inline static bool _usingFakenvapiAsMainNvapi = false; - inline static bool _usingOnNvidia = false; - inline static void* _lowLatencyTechContext = nullptr; - inline static LowLatencyMode _lowLatencyMode = LowLatencyMode::LatencyFlex; - inline static HMODULE _dllForNvidia = nullptr; static std::unordered_map idToFuncMapping; - static bool updateModeAndContext(); - static NvAPI_Status __cdecl placeholder() { // return OK(); @@ -25,13 +19,7 @@ class fakenvapi } public: - static void init(bool onlyContext); - static void deinit(); static void* queryInterface(NvU32 id); - static bool isLowLatencyActive(); - - static LowLatencyMode getCurrentMode(); - static bool isUsingAsMainNvapi(); static void setUsingAsMainNvapi(bool usingAsMain); }; diff --git a/OptiScaler/nvapi/fakenvapi/low_latency.cpp b/OptiScaler/nvapi/fakenvapi/low_latency.cpp deleted file mode 100644 index 0b19a91d..00000000 --- a/OptiScaler/nvapi/fakenvapi/low_latency.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include "pch.h" -#include "low_latency.h" - -// private -void LowLatency::update_effective_fg_state() -{ - if (auto current_tech = currently_active_tech.load()) - { - if (!current_tech) - return; - - current_tech->set_effective_fg_state(fg); - } -} - -void LowLatency::update_enabled_override() -{ - if (auto current_tech = currently_active_tech.load()) - { - if (!current_tech) - return; - - current_tech->set_low_latency_override((ForceReflex) Config::Instance()->FN_ForceReflex.value_or_default()); - } -} - -// public -bool LowLatency::deinit_current_tech() -{ - // currently_active_tech becomes nullptr - // but we need to wait for all users of the old one to release - auto old_tech = currently_active_tech.exchange(nullptr); - - if (old_tech) - { - LOG_TRACE("Deiniting current tech"); - while (old_tech.use_count() > 1) - std::this_thread::yield(); - - old_tech->deinit(); - - std::memset(frame_reports, 0, sizeof(frame_reports)); - - return true; - } - - return false; -} - -bool LowLatency::get_low_latency_tech_context(void** low_latency_context, LowLatencyMode* low_latency_tech) -{ - if (auto current_tech = currently_active_tech.load()) - { - if (!current_tech || !low_latency_context || !low_latency_tech) - return false; - - *low_latency_context = current_tech->get_tech_context(); - *low_latency_tech = current_tech->get_mode(); - } - - // We are during deinit, don't let app use the context - if (delay_deinit > 0) - { - *low_latency_context = nullptr; - delay_deinit = 1; - } - - return true; -} - -bool LowLatency::is_low_latency_enabled() -{ - auto current_tech = currently_active_tech.load(); - - if (!current_tech) - return false; - - return current_tech->is_enabled(); -} \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/low_latency.h b/OptiScaler/nvapi/fakenvapi/low_latency.h deleted file mode 100644 index b0baab68..00000000 --- a/OptiScaler/nvapi/fakenvapi/low_latency.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include "low_latency/low_latency_tech/low_latency_tech.h" - -#include -#include - -#include "low_latency/ll_util.h" -#include - -class LowLatency -{ - private: - std::atomic> currently_active_tech; - FrameReport frame_reports[FRAME_REPORTS_BUFFER_SIZE] {}; - bool fg; - uint32_t delay_deinit = 0; - SleepMode last_sleep_mode {}; - - void update_effective_fg_state(); - void update_enabled_override(); - - // D3D - bool update_low_latency_tech(IUnknown* pDevice); - void get_latency_result(NV_LATENCY_RESULT_PARAMS* pGetLatencyParams); - void add_marker_to_report(NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); - - // Vulkan - bool update_low_latency_tech(HANDLE vkDevice); - void get_latency_result(NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams); - void add_marker_to_report(NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); - - public: - LowLatency() = default; - ~LowLatency() { deinit_current_tech(); }; - - bool deinit_current_tech(); - bool get_low_latency_tech_context(void** low_latency_tech_context, LowLatencyMode* low_latency_tech); - - bool is_low_latency_enabled(); - - // D3D - NvAPI_Status Sleep(IUnknown* pDevice); - NvAPI_Status SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); - NvAPI_Status GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams); - NvAPI_Status SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); - NvAPI_Status SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, - NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams); - NvAPI_Status GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams); - - // Vulkan - NvAPI_Status Sleep(HANDLE vkDevice); - NvAPI_Status SetSleepMode(HANDLE vkDevice, NV_VULKAN_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); - NvAPI_Status GetSleepStatus(HANDLE vkDevice, NV_VULKAN_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams); - NvAPI_Status SetLatencyMarker(HANDLE vkDevice, NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); - NvAPI_Status GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams); -}; - -// This is a wrapper for the entire LowLatency abstraction layer -// If you need a specific *tech* context then you need to query this abstraction layer -class LowLatencyCtx -{ - public: - static void init() - { - if (!lowlatency_ctx) - lowlatency_ctx = new LowLatency(); - } - - static void shutdown() - { - delete lowlatency_ctx; - lowlatency_ctx = nullptr; - } - - static LowLatency* get() { return lowlatency_ctx; } - - private: - static LowLatency* lowlatency_ctx; -}; diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp deleted file mode 100644 index 2fb23656..00000000 --- a/OptiScaler/nvapi/fakenvapi/low_latency_d3d.cpp +++ /dev/null @@ -1,327 +0,0 @@ -#include "pch.h" -#include "low_latency.h" - -#include "low_latency/low_latency_tech/ll_antilag2.h" -#include "low_latency/low_latency_tech/ll_latencyflex.h" -#include "low_latency/low_latency_tech/ll_xell.h" - -#include "log.h" -#include "config.h" -#include -#include - -// private -bool LowLatency::update_low_latency_tech(IUnknown* pDevice) -{ - if (!pDevice) - { - LOG_ERROR("Invalid pointer"); - return false; - } - - if (!currently_active_tech.load()) - { - // Don't use AL2 and XeLL when using DMFG - if (!Config::Instance()->FN_ForceLatencyFlex.value_or_default() && - State::Instance().dlssgLastSetMode != sl::DLSSGMode::eDynamic) - { - auto new_tech_al2 = std::make_shared(); - if (new_tech_al2->init(pDevice)) - { - LOG_INFO("LowLatency algo: FSR Anti-Lag 2.0"); - new_tech_al2->set_sleep_mode(&last_sleep_mode); - currently_active_tech.store(std::move(new_tech_al2)); - return true; - } - - auto new_tech_xell = std::make_shared(); - if (new_tech_xell->init(pDevice)) - { - LOG_INFO("LowLatency algo: XeLL"); - new_tech_xell->set_sleep_mode(&last_sleep_mode); - currently_active_tech.store(std::move(new_tech_xell)); - return true; - } - } - - auto new_tech = std::make_shared(); - if (new_tech->init(pDevice)) - { - LOG_INFO("LowLatency algo: LatencyFlex"); - new_tech->set_sleep_mode(&last_sleep_mode); - currently_active_tech.store(std::move(new_tech)); - return true; - } - } - - static bool last_force_latencyflex = Config::Instance()->FN_ForceLatencyFlex.value_or_default(); - bool force_latencyflex = Config::Instance()->FN_ForceLatencyFlex.value_or_default(); - bool change_detected = last_force_latencyflex != force_latencyflex; - last_force_latencyflex = force_latencyflex; - - if (State::Instance().fakenvapiReloadLowLatency) - { - change_detected = true; - State::Instance().fakenvapiReloadLowLatency = false; - } - - auto try_reinit = [&]() -> bool - { - if (!deinit_current_tech()) - { - LOG_ERROR("Couldn't deinitialize low latency tech"); - return false; - } - return update_low_latency_tech(pDevice); - }; - - // FSR FG might still be using AntiLag 2, give Opti time to set AL2 context to null - if (change_detected) - { - bool al2 = false; - bool xell = false; - { - auto current_tech = currently_active_tech.load(); - if (current_tech) - { - auto mode = current_tech->get_mode(); - al2 = mode == LowLatencyMode::AntiLag2; - xell = mode == LowLatencyMode::XeLL; - } - } - - if (al2 || xell) - { - delay_deinit = 50; - } - else - { - return try_reinit(); - } - } - - if (delay_deinit > 0) - { - if (--delay_deinit == 0) - return try_reinit(); - } - - return true; -} - -void LowLatency::get_latency_result(NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (pGetLatencyParams->version != NV_LATENCY_RESULT_PARAMS_VER1) - { - LOG_ERROR("GetLatency: Unsupported version {}", pGetLatencyParams->version); - return; - } - - // Assume no frame reports collected yet, report all zeros - if (frame_reports[FRAME_REPORTS_BUFFER_SIZE - 1].frameID == 0) - { - std::memset(pGetLatencyParams->frameReport, 0, sizeof(pGetLatencyParams->frameReport)); - // spdlog::warn("GetLatency: Not enough data to report"); - return; - } - - // Sort frame reports, find the oldest - size_t minIdx = 0; - uint64_t minID = frame_reports[0].frameID; - for (size_t i = 1; i < FRAME_REPORTS_BUFFER_SIZE; i++) - { - if (frame_reports[i].frameID < minID) - { - minID = frame_reports[i].frameID; - minIdx = i; - } - } - - // Copy starting from older before wrapping around - size_t firstChunk = std::min(NVAPI_BUFFER_SIZE, FRAME_REPORTS_BUFFER_SIZE - minIdx); - std::memcpy(pGetLatencyParams->frameReport, frame_reports + minIdx, firstChunk * sizeof(FrameReport)); - - // Copy the rest after wrapping around - if (firstChunk < NVAPI_BUFFER_SIZE) - { - std::memcpy(pGetLatencyParams->frameReport + firstChunk, frame_reports, - (NVAPI_BUFFER_SIZE - firstChunk) * sizeof(FrameReport)); - } -} - -void LowLatency::add_marker_to_report(NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - auto current_timestamp = Util::GetTimestamp() / 1000; - static auto last_sim_start = current_timestamp; - static auto _2nd_last_sim_start = current_timestamp; - auto current_report = &frame_reports[pSetLatencyMarkerParams->frameID % FRAME_REPORTS_BUFFER_SIZE]; - - if (current_report->frameID != pSetLatencyMarkerParams->frameID) - { - *current_report = FrameReport {}; - } - - current_report->frameID = pSetLatencyMarkerParams->frameID; - current_report->gpuFrameTimeUs = (uint32_t) (last_sim_start - _2nd_last_sim_start); - current_report->gpuActiveRenderTimeUs = 100; - current_report->driverStartTime = current_timestamp; - current_report->driverEndTime = current_timestamp + 100; - current_report->gpuRenderStartTime = current_timestamp; - current_report->gpuRenderEndTime = current_timestamp + 100; - current_report->osRenderQueueStartTime = current_timestamp; - current_report->osRenderQueueEndTime = current_timestamp + 100; - switch (pSetLatencyMarkerParams->markerType) - { - case SIMULATION_START: - _2nd_last_sim_start = last_sim_start; - last_sim_start = Util::GetTimestamp() / 1000; - current_report->simStartTime = last_sim_start; - break; - case SIMULATION_END: - current_report->simEndTime = Util::GetTimestamp() / 1000; - break; - case RENDERSUBMIT_START: - current_report->renderSubmitStartTime = Util::GetTimestamp() / 1000; - break; - case RENDERSUBMIT_END: - current_report->renderSubmitEndTime = Util::GetTimestamp() / 1000; - break; - case PRESENT_START: - current_report->presentStartTime = Util::GetTimestamp() / 1000; - break; - case PRESENT_END: - current_report->presentEndTime = Util::GetTimestamp() / 1000; - break; - case INPUT_SAMPLE: - current_report->inputSampleTime = Util::GetTimestamp() / 1000; - break; - default: - break; - } -} - -// public -NvAPI_Status LowLatency::Sleep(IUnknown* pDevice) -{ - if (!update_low_latency_tech(pDevice)) - return ERROR(); - - if (auto current_tech = currently_active_tech.load()) - current_tech->sleep(); - - return OK(); -} - -NvAPI_Status LowLatency::SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) -{ - if (!update_low_latency_tech(pDevice)) - return ERROR(); - - last_sleep_mode.low_latency_enabled = pSetSleepModeParams->bLowLatencyMode; - last_sleep_mode.low_latency_boost = pSetSleepModeParams->bLowLatencyBoost; - last_sleep_mode.minimum_interval_us = pSetSleepModeParams->minimumIntervalUs; - last_sleep_mode.use_markers_to_optimize = pSetSleepModeParams->bUseMarkersToOptimize; - - if (auto current_tech = currently_active_tech.load()) - current_tech->set_sleep_mode(&last_sleep_mode); - - return OK(); -} - -NvAPI_Status LowLatency::GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) -{ - if (!update_low_latency_tech(pDevice)) - return ERROR(); - - SleepParams sleep_params {}; - - if (auto current_tech = currently_active_tech.load()) - current_tech->get_sleep_status(&sleep_params); - - pGetSleepStatusParams->bLowLatencyMode = sleep_params.low_latency_enabled; - pGetSleepStatusParams->bFsVrr = sleep_params.fullscreen_vrr; - pGetSleepStatusParams->bCplVsyncOn = sleep_params.control_panel_vsync_override; - - return OK(); -} - -NvAPI_Status LowLatency::SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - if (!update_low_latency_tech(pDev)) - return ERROR(); - - update_effective_fg_state(); - - update_enabled_override(); - - add_marker_to_report(pSetLatencyMarkerParams); - - MarkerParams marker_params {}; - - marker_params.frame_id = pSetLatencyMarkerParams->frameID; - marker_params.marker_type = (MarkerType) pSetLatencyMarkerParams->markerType; // requires enums to match - - if (auto current_tech = currently_active_tech.load()) - current_tech->set_marker(pDev, marker_params); - - LOG_TRACE_FAKENVAPI("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id); - - return NVAPI_OK; -} - -NvAPI_Status LowLatency::SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, - NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) -{ - if (!currently_active_tech.load()) // can't init using ID3D12CommandQueue, can only check if available - return ERROR(); - - MarkerParams marker_params {}; - - marker_params.frame_id = pSetAsyncFrameMarkerParams->frameID; - marker_params.marker_type = (MarkerType) pSetAsyncFrameMarkerParams->markerType; // requires enums to match - - if (marker_params.marker_type == MarkerType::OUT_OF_BAND_PRESENT_START) - { - constexpr size_t history_size = 12; - static size_t counter = 0; - static NvU64 previous_frame_ids[history_size] = {}; - - previous_frame_ids[counter % history_size] = pSetAsyncFrameMarkerParams->frameID; - counter++; - - int repeat_count = 0; - - for (size_t i = 1; i < history_size; i++) - { - // won't catch repeat frame ids across array wrap around - if (previous_frame_ids[i] == previous_frame_ids[i - 1]) - { - repeat_count++; - } - } - - if (fg && repeat_count == 0) - fg = false; - else if (!fg && repeat_count >= history_size / 2 - 1) - fg = true; - - update_effective_fg_state(); - } - - if (auto current_tech = currently_active_tech.load()) - current_tech->set_async_marker(pCommandQueue, marker_params); - - LOG_TRACE_FAKENVAPI("Async {}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id); - - return NVAPI_OK; -} - -NvAPI_Status LowLatency::GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (!update_low_latency_tech(pDev)) - return ERROR(); - - get_latency_result(pGetLatencyParams); - - return OK(); -} diff --git a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp b/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp deleted file mode 100644 index 9fb85548..00000000 --- a/OptiScaler/nvapi/fakenvapi/low_latency_vk.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "pch.h" -#include "low_latency.h" - -#include "low_latency/low_latency_tech/ll_antilag_vk.h" -#include "low_latency/low_latency_tech/ll_latencyflex.h" - -#include "log.h" -#include "config.h" - -// private -bool LowLatency::update_low_latency_tech(HANDLE vkDevice) -{ - if (!currently_active_tech.load()) - { - if (!Config::Instance()->FN_ForceLatencyFlex.value_or_default()) - { - auto new_tech = std::make_shared(); - if (new_tech->init(nullptr)) - { - LOG_INFO("LowLatency algo: AntiLag Vulkan"); - currently_active_tech.store(std::move(new_tech)); - return true; - } - } - - auto new_tech = std::make_shared(); - if (new_tech->init(nullptr)) - { - LOG_INFO("LowLatency algo: LatencyFlex"); - currently_active_tech.store(std::move(new_tech)); - return true; - } - } - - static bool last_force_latencyflex = Config::Instance()->FN_ForceLatencyFlex.value_or_default(); - bool force_latencyflex = Config::Instance()->FN_ForceLatencyFlex.value_or_default(); - bool change_detected = last_force_latencyflex != force_latencyflex; - last_force_latencyflex = force_latencyflex; - - if (State::Instance().fakenvapiReloadLowLatency) - { - change_detected = true; - State::Instance().fakenvapiReloadLowLatency = false; - } - - if (change_detected) - { - if (deinit_current_tech()) - { - return update_low_latency_tech((HANDLE) nullptr); // call again to reinit - } - else - { - LOG_ERROR("Couldn't deinitialize low latency tech"); - return false; - } - } - - return true; -} - -void LowLatency::get_latency_result(NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (pGetLatencyParams->version != NV_VULKAN_LATENCY_RESULT_PARAMS_VER1) - { - LOG_ERROR("GetLatency: Unsupported version {}", pGetLatencyParams->version); - return; - } - - // Assume no frame reports collected yet, report all zeros - if (frame_reports[FRAME_REPORTS_BUFFER_SIZE - 1].frameID == 0) - { - std::memset(pGetLatencyParams->frameReport, 0, sizeof(pGetLatencyParams->frameReport)); - // spdlog::warn("GetLatency: Not enough data to report"); - return; - } - - // Sort frame reports, find the oldest - size_t minIdx = 0; - uint64_t minID = frame_reports[0].frameID; - for (size_t i = 1; i < FRAME_REPORTS_BUFFER_SIZE; i++) - { - if (frame_reports[i].frameID < minID) - { - minID = frame_reports[i].frameID; - minIdx = i; - } - } - - // Copy starting from older before wrapping around - size_t firstChunk = std::min(NVAPI_BUFFER_SIZE, FRAME_REPORTS_BUFFER_SIZE - minIdx); - std::memcpy(pGetLatencyParams->frameReport, frame_reports + minIdx, firstChunk * sizeof(FrameReport)); - - // Copy the rest after wrapping around - if (firstChunk < NVAPI_BUFFER_SIZE) - { - std::memcpy(pGetLatencyParams->frameReport + firstChunk, frame_reports, - (NVAPI_BUFFER_SIZE - firstChunk) * sizeof(FrameReport)); - } - - // gpuFrameTimeUs and gpuActiveRenderTimeUs are missing in the vk struct - for (auto i = 0; i < NVAPI_BUFFER_SIZE; i++) - { - std::memset(&pGetLatencyParams->frameReport[i].rsvd[0], 0, - sizeof(FrameReport::gpuFrameTimeUs) + sizeof(FrameReport::gpuActiveRenderTimeUs)); - } -} - -void LowLatency::add_marker_to_report(NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - auto current_timestamp = Util::GetTimestamp() / 1000; - static auto last_sim_start = current_timestamp; - static auto _2nd_last_sim_start = current_timestamp; - auto current_report = &frame_reports[pSetLatencyMarkerParams->frameID % FRAME_REPORTS_BUFFER_SIZE]; - - if (current_report->frameID != pSetLatencyMarkerParams->frameID) - { - *current_report = FrameReport {}; - } - - current_report->frameID = pSetLatencyMarkerParams->frameID; - current_report->gpuFrameTimeUs = (uint32_t) (last_sim_start - _2nd_last_sim_start); - current_report->gpuActiveRenderTimeUs = 100; - current_report->driverStartTime = current_timestamp; - current_report->driverEndTime = current_timestamp + 100; - current_report->gpuRenderStartTime = current_timestamp; - current_report->gpuRenderEndTime = current_timestamp + 100; - current_report->osRenderQueueStartTime = current_timestamp; - current_report->osRenderQueueEndTime = current_timestamp + 100; - switch (pSetLatencyMarkerParams->markerType) - { - case VULKAN_SIMULATION_START: - _2nd_last_sim_start = last_sim_start; - last_sim_start = Util::GetTimestamp() / 1000; - current_report->simStartTime = last_sim_start; - break; - case VULKAN_SIMULATION_END: - current_report->simEndTime = Util::GetTimestamp() / 1000; - break; - case VULKAN_RENDERSUBMIT_START: - current_report->renderSubmitStartTime = Util::GetTimestamp() / 1000; - break; - case VULKAN_RENDERSUBMIT_END: - current_report->renderSubmitEndTime = Util::GetTimestamp() / 1000; - break; - case VULKAN_PRESENT_START: - current_report->presentStartTime = Util::GetTimestamp() / 1000; - break; - case VULKAN_PRESENT_END: - current_report->presentEndTime = Util::GetTimestamp() / 1000; - break; - case VULKAN_INPUT_SAMPLE: - current_report->inputSampleTime = Util::GetTimestamp() / 1000; - break; - default: - break; - } -} - -// public -NvAPI_Status LowLatency::Sleep(HANDLE vkDevice) -{ - if (!update_low_latency_tech(vkDevice)) - return ERROR(); - - if (auto current_tech = currently_active_tech.load()) - current_tech->sleep(); - - return OK(); -} - -NvAPI_Status LowLatency::SetSleepMode(HANDLE vkDevice, NV_VULKAN_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) -{ - if (!update_low_latency_tech(vkDevice)) - return ERROR(); - - SleepMode sleep_mode {}; - - sleep_mode.low_latency_enabled = pSetSleepModeParams->bLowLatencyMode; - sleep_mode.low_latency_boost = pSetSleepModeParams->bLowLatencyBoost; - sleep_mode.minimum_interval_us = pSetSleepModeParams->minimumIntervalUs; - sleep_mode.use_markers_to_optimize = true; - - if (auto current_tech = currently_active_tech.load()) - current_tech->set_sleep_mode(&sleep_mode); - - return OK(); -} - -NvAPI_Status LowLatency::GetSleepStatus(HANDLE vkDevice, NV_VULKAN_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) -{ - if (!update_low_latency_tech(vkDevice)) - return ERROR(); - - SleepParams sleep_params {}; - - if (auto current_tech = currently_active_tech.load()) - current_tech->get_sleep_status(&sleep_params); - - pGetSleepStatusParams->bLowLatencyMode = sleep_params.low_latency_enabled; - - return OK(); -} - -NvAPI_Status LowLatency::SetLatencyMarker(HANDLE vkDevice, NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - if (!update_low_latency_tech(vkDevice)) - return ERROR(); - - update_effective_fg_state(); - - update_enabled_override(); - - add_marker_to_report(pSetLatencyMarkerParams); - - MarkerParams marker_params {}; - - marker_params.frame_id = pSetLatencyMarkerParams->frameID; - marker_params.marker_type = (MarkerType) pSetLatencyMarkerParams->markerType; // requires enums to match - - // This cast is not ideal as it needs to be cast to VkDevice while knowing it's vulkan - if (auto current_tech = currently_active_tech.load()) - current_tech->set_marker((IUnknown*) vkDevice, marker_params); - - LOG_TRACE_FAKENVAPI("{}: {}", magic_enum::enum_name(marker_params.marker_type), marker_params.frame_id); - - return NVAPI_OK; -} - -NvAPI_Status LowLatency::GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (!update_low_latency_tech(vkDevice)) - return ERROR(); - - get_latency_result(pGetLatencyParams); - - return OK(); -} diff --git a/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp b/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp index bdd01145..5ffb14e0 100644 --- a/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi_calls.cpp @@ -3,11 +3,9 @@ #include "proxies/Dxgi_Proxy.h" #include #include -#include using Microsoft::WRL::ComPtr; -LowLatency* LowLatencyCtx::lowlatency_ctx = nullptr; static auto init_mutex = std::mutex {}; namespace nvapi_calls @@ -346,47 +344,6 @@ NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUn NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { return ERROR_VALUE(NVAPI_NO_IMPLEMENTATION); } -NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) -{ - if (!pDevice || !pGetSleepStatusParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->GetSleepStatus(pDevice, pGetSleepStatusParams); -} - -NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDevice, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (!pDevice || !pGetLatencyParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - // xellGetFramesReports() currently doesn't give any extra data that we can't already get - return LowLatencyCtx::get()->GetLatency(pDevice, pGetLatencyParams); -} - -NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) -{ - if (!pDevice || !pSetSleepModeParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->SetSleepMode(pDevice, pSetSleepModeParams); -} - -NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDevice, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - if (!pDevice || !pSetLatencyMarkerParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->SetLatencyMarker(pDevice, pSetLatencyMarkerParams); -} - -NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) -{ - if (!pDevice) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->Sleep(pDevice); -} - NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDevice, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { return OK(); @@ -600,105 +557,6 @@ NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* return OK(); } -NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, - NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) -{ - if (pSetAsyncFrameMarkerParams == nullptr) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->SetAsyncFrameMarker(pCommandQueue, pSetAsyncFrameMarkerParams); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_InitLowLatencyDevice(HANDLE vkDevice, HANDLE* signalSemaphoreHandle) -{ - if (!vkDevice || !signalSemaphoreHandle) - return ERROR(); - - VkDevice device = reinterpret_cast(vkDevice); - - VkSemaphoreTypeCreateInfo timelineInfo {}; - timelineInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; - timelineInfo.pNext = nullptr; - timelineInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; - timelineInfo.initialValue = 0; - - VkSemaphoreCreateInfo createInfo {}; - createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - createInfo.pNext = &timelineInfo; - createInfo.flags = 0; - - VkResult res = VK_ERROR_UNKNOWN; - - if (VulkanHooks::o_vkCreateSemaphore && low_latency_semaphore == VK_NULL_HANDLE) - res = VulkanHooks::o_vkCreateSemaphore(device, &createInfo, nullptr, &low_latency_semaphore); - - if (res != VK_SUCCESS) - return NVAPI_ERROR; - - *signalSemaphoreHandle = reinterpret_cast(low_latency_semaphore); - - // It happens automatically on every reflex call - return OK(); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_DestroyLowLatencyDevice(HANDLE vkDevice) -{ - LowLatencyCtx::get()->deinit_current_tech(); - return OK(); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_GetSleepStatus(HANDLE vkDevice, - NV_VULKAN_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) -{ - if (!vkDevice || !pGetSleepStatusParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->GetSleepStatus(vkDevice, pGetSleepStatusParams); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_SetSleepMode(HANDLE vkDevice, NV_VULKAN_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) -{ - if (!vkDevice || !pSetSleepModeParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->SetSleepMode(vkDevice, pSetSleepModeParams); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_Sleep(HANDLE vkDevice, NvU64 signalValue) -{ - if (!vkDevice) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - VkSemaphoreSignalInfo signalInfo {}; - signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - signalInfo.pNext = nullptr; - signalInfo.semaphore = low_latency_semaphore; - signalInfo.value = signalValue; - - VkDevice device = reinterpret_cast(vkDevice); - - VulkanHooks::SignalSemaphore(device, &signalInfo); - - return LowLatencyCtx::get()->Sleep(vkDevice); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams) -{ - if (!vkDevice || !pGetLatencyParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->GetLatency(vkDevice, pGetLatencyParams); -} - -NvAPI_Status __cdecl NvAPI_Vulkan_SetLatencyMarker(HANDLE vkDevice, - NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) -{ - if (!vkDevice || !pSetLatencyMarkerParams) - return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); - - return LowLatencyCtx::get()->SetLatencyMarker(vkDevice, pSetLatencyMarkerParams); -} - NvAPI_Status __cdecl NvAPI_Vulkan_NotifyOutOfBandVkQueue(HANDLE vkDevice, HANDLE queueHandle, NV_VULKAN_OUT_OF_BAND_QUEUE_TYPE queueType) { @@ -770,15 +628,7 @@ NvAPI_Status __cdecl NvAPI_Unload() if (ref_count == 0) return ERROR_VALUE(NVAPI_API_NOT_INITIALIZED); - if (--ref_count == 0) - { - auto context = LowLatencyCtx::get(); - - if (!context) - return ERROR(); - - context->deinit_current_tech(); - } + --ref_count; return OK(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi_calls.h b/OptiScaler/nvapi/fakenvapi/nvapi_calls.h index 1a7acf86..d14b195a 100644 --- a/OptiScaler/nvapi/fakenvapi/nvapi_calls.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi_calls.h @@ -4,8 +4,6 @@ #include #include -#include "low_latency.h" - #include "low_latency/ll_util.h" #include "log.h" @@ -17,8 +15,6 @@ static auto drs_profile = reinterpret_cast(&drs); static uint64_t ref_count = 0; -static VkSemaphore low_latency_semaphore = VK_NULL_HANDLE; - NvAPI_Status __cdecl NvAPI_Initialize(); NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc); NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count); @@ -67,11 +63,6 @@ NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, N NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle); NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint(); -NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams); -NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams); -NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); -NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); -NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice); NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams); NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported); NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext); @@ -87,17 +78,6 @@ NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx( ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams); NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType); -NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, - NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams); -NvAPI_Status __cdecl NvAPI_Vulkan_InitLowLatencyDevice(HANDLE vkDevice, HANDLE* signalSemaphoreHandle); -NvAPI_Status __cdecl NvAPI_Vulkan_DestroyLowLatencyDevice(HANDLE vkDevice); -NvAPI_Status __cdecl NvAPI_Vulkan_GetSleepStatus(HANDLE vkDevice, - NV_VULKAN_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams); -NvAPI_Status __cdecl NvAPI_Vulkan_SetSleepMode(HANDLE vkDevice, NV_VULKAN_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); -NvAPI_Status __cdecl NvAPI_Vulkan_Sleep(HANDLE vkDevice, NvU64 signalValue); -NvAPI_Status __cdecl NvAPI_Vulkan_GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams); -NvAPI_Status __cdecl NvAPI_Vulkan_SetLatencyMarker(HANDLE vkDevice, - NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); NvAPI_Status __cdecl NvAPI_Vulkan_NotifyOutOfBandVkQueue(HANDLE vkDevice, HANDLE queueHandle, NV_VULKAN_OUT_OF_BAND_QUEUE_TYPE queueType); NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session);