mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-11-05 13:33:08 +00:00
Lobotomize fakenvapi
Alternative titles: complete the move of low latency code out of fakenvapi
This commit is contained in:
1 parent
a79c2f34b4
commit
5dfedd6836
18 files changed
+47
-1136
No files matched your search
@@ -270,7 +270,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
|
||||
<ClInclude Include="shaders\hudless_compare_compute\HCC_Dx12.h" />
|
||||
<ClInclude Include="low_latency\ll_util.h" />
|
||||
<ClInclude Include="nvapi\fakenvapi\log.h" />
|
||||
<ClInclude Include="nvapi\fakenvapi\low_latency.h" />
|
||||
<ClInclude Include="low_latency\low_latency_tech\ll_antilag2.h" />
|
||||
<ClInclude Include="low_latency\low_latency_tech\ll_antilag_vk.h" />
|
||||
<ClInclude Include="low_latency\low_latency_tech\ll_latencyflex.h" />
|
||||
@@ -618,8 +617,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
|
||||
<ClCompile Include="inputs\XeSS_Dx11.cpp" />
|
||||
<ClCompile Include="low_latency\ll_util.cpp" />
|
||||
<ClCompile Include="nvapi\fakenvapi\log.cpp" />
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency.cpp" />
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency_d3d.cpp" />
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_antilag2.cpp" />
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_antilag_vk.cpp" />
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_latencyflex.cpp" />
|
||||
@@ -627,7 +624,6 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_reflex.cpp" />
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_reflex_vk.cpp" />
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_xell.cpp" />
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency_vk.cpp" />
|
||||
<ClCompile Include="nvapi\fakenvapi\nvapi_calls.cpp" />
|
||||
<ClCompile Include="framegen\nvngx\Nvngx_FFX.cpp" />
|
||||
<ClCompile Include="framegen\nvngx\Nvngx_Nukems.cpp" />
|
||||
|
||||
@@ -806,9 +806,6 @@
|
||||
<ClInclude Include="nvapi\fakenvapi\log.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nvapi\fakenvapi\low_latency.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="low_latency\low_latency_tech\ll_antilag2.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -1604,12 +1601,6 @@
|
||||
<ClCompile Include="nvapi\fakenvapi\log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency_d3d.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_antilag2.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -1631,9 +1622,6 @@
|
||||
<ClCompile Include="low_latency\low_latency_tech\ll_xell.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nvapi\fakenvapi\low_latency_vk.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="nvapi\fakenvapi\nvapi_calls.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#include "Reflex_Hooks.h"
|
||||
#include <Config.h>
|
||||
|
||||
#include <nvapi/fakenvapi.h>
|
||||
|
||||
#include <proxies/Streamline_Proxy.h>
|
||||
|
||||
#include <magic_enum.hpp>
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 <typename Fn> static Fn ToDriver(unsigned int id)
|
||||
{
|
||||
if (fakenvapi::isUsingAsMainNvapi())
|
||||
if (!InputCommon::driver_reflex_available(API::DX12))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<Fn>(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);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <hooks/LibraryLoad_Hooks.h>
|
||||
#include <nvapi/NvApiHooks.h>
|
||||
#include <low_latency/input/input_common.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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<float>(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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,20 +12,6 @@
|
||||
|
||||
std::unordered_map<NvU32, void*> 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; }
|
||||
@@ -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<NvU32, void*> 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);
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "low_latency/low_latency_tech/low_latency_tech.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include "low_latency/ll_util.h"
|
||||
#include <optional>
|
||||
|
||||
class LowLatency
|
||||
{
|
||||
private:
|
||||
std::atomic<std::shared_ptr<LowLatencyTech>> 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;
|
||||
};
|
||||
@@ -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 <hooks/Reflex_Hooks.h>
|
||||
#include <framegen/nvngx/Nvngx_FG.h>
|
||||
|
||||
// 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<AntiLag2>();
|
||||
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<XeLL>();
|
||||
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<LatencyFlex>();
|
||||
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<uint64_t>(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();
|
||||
}
|
||||
@@ -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<AntiLagVk>();
|
||||
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<LatencyFlex>();
|
||||
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<uint64_t>(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();
|
||||
}
|
||||
@@ -3,11 +3,9 @@
|
||||
#include "proxies/Dxgi_Proxy.h"
|
||||
#include <misc/IdentifyGpu.h>
|
||||
#include <NvApiDriverSettings.h>
|
||||
#include <hooks/Vulkan_Hooks.h>
|
||||
|
||||
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>(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<HANDLE>(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>(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();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include <d3d12.h>
|
||||
#include <vector>
|
||||
|
||||
#include "low_latency.h"
|
||||
|
||||
#include "low_latency/ll_util.h"
|
||||
#include "log.h"
|
||||
|
||||
@@ -17,8 +15,6 @@ static auto drs_profile = reinterpret_cast<NvDRSProfileHandle>(&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);
|
||||
|
||||
Reference in new issue
Block a user