From 099da43adeda4e8deef9528127f2b54d11fafe01 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Sun, 22 Mar 2026 19:45:24 +0100 Subject: [PATCH] Adding Vulkan support to the reflex markers graph It behaves a bit differently than with D3D --- OptiScaler/hooks/Reflex_Hooks.cpp | 113 +++++++++++++++++++----------- OptiScaler/hooks/Reflex_Hooks.h | 3 + 2 files changed, 77 insertions(+), 39 deletions(-) diff --git a/OptiScaler/hooks/Reflex_Hooks.cpp b/OptiScaler/hooks/Reflex_Hooks.cpp index 72fa3a2e..2b03e202 100644 --- a/OptiScaler/hooks/Reflex_Hooks.cpp +++ b/OptiScaler/hooks/Reflex_Hooks.cpp @@ -221,6 +221,15 @@ NvAPI_Status ReflexHooks::hkNvAPI_Vulkan_SetSleepMode(HANDLE vkDevice, return o_NvAPI_Vulkan_SetSleepMode(vkDevice, pSetSleepModeParams); } +NvAPI_Status ReflexHooks::hkNvAPI_Vulkan_GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams) +{ +#ifdef LOG_REFLEX_CALLS + LOG_FUNC(); +#endif + + return o_NvAPI_Vulkan_GetLatency(vkDevice, pGetLatencyParams); +} + void ReflexHooks::hookReflex(PFN_NvApi_QueryInterface& queryInterface) { if (!_inited) @@ -236,9 +245,11 @@ void ReflexHooks::hookReflex(PFN_NvApi_QueryInterface& queryInterface) o_NvAPI_D3D12_SetAsyncFrameMarker = GET_INTERFACE(NvAPI_D3D12_SetAsyncFrameMarker, queryInterface); o_NvAPI_Vulkan_SetLatencyMarker = GET_INTERFACE(NvAPI_Vulkan_SetLatencyMarker, queryInterface); o_NvAPI_Vulkan_SetSleepMode = GET_INTERFACE(NvAPI_Vulkan_SetSleepMode, queryInterface); + o_NvAPI_Vulkan_GetLatency = GET_INTERFACE(NvAPI_Vulkan_GetLatency, queryInterface); _inited = o_NvAPI_D3D_SetSleepMode && o_NvAPI_D3D_Sleep && o_NvAPI_D3D_GetLatency && - o_NvAPI_D3D_SetLatencyMarker && o_NvAPI_D3D12_SetAsyncFrameMarker; + o_NvAPI_D3D_SetLatencyMarker && o_NvAPI_D3D12_SetAsyncFrameMarker && + o_NvAPI_Vulkan_SetLatencyMarker && o_NvAPI_Vulkan_SetSleepMode && o_NvAPI_Vulkan_GetLatency; if (_inited) LOG_DEBUG("Inited Reflex hooks"); @@ -281,6 +292,10 @@ void* ReflexHooks::getHookedReflex(unsigned int InterfaceId) { return &hkNvAPI_Vulkan_SetSleepMode; } + if (InterfaceId == GET_ID(NvAPI_Vulkan_GetLatency) && o_NvAPI_Vulkan_GetLatency) + { + return &hkNvAPI_Vulkan_GetLatency; + } return nullptr; } @@ -301,52 +316,72 @@ bool ReflexHooks::updateTimingData() { bool canCall = ((State::Instance().activeFgOutput == FGOutput::XeFG && !fakenvapi::isUsingAsMainNvapi() && !Config::Instance()->XeFGWithoutXeLL.value_or_default()) || - o_NvAPI_D3D_GetLatency); + o_NvAPI_D3D_GetLatency || o_NvAPI_Vulkan_GetLatency); - if (!canCall || !_lastSleepDev) + if (!canCall) return false; - NV_LATENCY_RESULT_PARAMS results {}; - results.version = NV_LATENCY_RESULT_PARAMS_VER; - - if (auto result = hkNvAPI_D3D_GetLatency(_lastSleepDev, &results); result != NVAPI_OK) - return false; - - // 64th element have the latest data - auto& frameReport = results.frameReport[63]; - - uint64_t start = UINT64_MAX; - uint64_t end = 0; - - // Please don't look, just thought it would be least work - auto pTimes = (uint64_t*) &frameReport.simStartTime; - for (auto i = 0; i < 11; i++) + auto processFrameReport = [&](const auto& frameReport) -> bool { - auto& time = pTimes[i]; - if (time == 0) - continue; + uint64_t start = UINT64_MAX; + uint64_t end = 0; - if (time < start) - start = time; + // Please don't look, just thought it would be least work + auto pTimes = (const uint64_t*) &frameReport.simStartTime; + for (auto i = 0; i < 11; i++) + { + auto& time = pTimes[i]; + if (time == 0) + continue; - if (time > end) - end = time; + if (time < start) + start = time; + + if (time > end) + end = time; + } + + if (end < start) + return false; + + double rangeNs = static_cast(end - start); + + timingData[TimingType::TimeRange] = TimingEntry { .position = 0, .length = rangeNs }; + UPDATE_TIMING_ENTRY(sim, Simulation) + UPDATE_TIMING_ENTRY(renderSubmit, RenderSubmit) + UPDATE_TIMING_ENTRY(present, Present) + UPDATE_TIMING_ENTRY(driver, Driver) + UPDATE_TIMING_ENTRY(osRenderQueue, OsRenderQueue) + UPDATE_TIMING_ENTRY(gpuRender, GpuRender) + + return true; + }; + + if (_lastSleepDev && o_NvAPI_D3D_GetLatency) + { + // Not calling free on this but it's static so hopefully fine + static NV_LATENCY_RESULT_PARAMS* results = new NV_LATENCY_RESULT_PARAMS(NV_LATENCY_RESULT_PARAMS_VER); + + if (auto result = hkNvAPI_D3D_GetLatency(_lastSleepDev, results); result != NVAPI_OK) + return false; + + // 64th element has the latest data + return processFrameReport(results->frameReport[63]); + } + else if (_lastVkSleepDev && o_NvAPI_Vulkan_GetLatency) + { + // Not calling free on this but it's static so hopefully fine + static NV_VULKAN_LATENCY_RESULT_PARAMS* results = + new NV_VULKAN_LATENCY_RESULT_PARAMS(NV_VULKAN_LATENCY_RESULT_PARAMS_VER); + + if (auto result = hkNvAPI_Vulkan_GetLatency(_lastVkSleepDev, results); result != NVAPI_OK) + return false; + + // 64th element has the latest data + return processFrameReport(results->frameReport[63]); } - if (end < start) - return false; - - double rangeNs = static_cast(end - start); - - timingData[TimingType::TimeRange] = TimingEntry { .position = 0, .length = rangeNs }; - UPDATE_TIMING_ENTRY(sim, Simulation) - UPDATE_TIMING_ENTRY(renderSubmit, RenderSubmit) - UPDATE_TIMING_ENTRY(present, Present) - UPDATE_TIMING_ENTRY(driver, Driver) - UPDATE_TIMING_ENTRY(osRenderQueue, OsRenderQueue) - UPDATE_TIMING_ENTRY(gpuRender, GpuRender) - - return true; + return false; } // For updating information about Reflex hooks diff --git a/OptiScaler/hooks/Reflex_Hooks.h b/OptiScaler/hooks/Reflex_Hooks.h index c9a3a8b9..eba19a5a 100644 --- a/OptiScaler/hooks/Reflex_Hooks.h +++ b/OptiScaler/hooks/Reflex_Hooks.h @@ -56,11 +56,13 @@ class ReflexHooks // Vulkan inline static decltype(&NvAPI_Vulkan_SetLatencyMarker) o_NvAPI_Vulkan_SetLatencyMarker = nullptr; inline static decltype(&NvAPI_Vulkan_SetSleepMode) o_NvAPI_Vulkan_SetSleepMode = nullptr; + inline static decltype(&NvAPI_Vulkan_GetLatency) o_NvAPI_Vulkan_GetLatency = nullptr; static NvAPI_Status hkNvAPI_Vulkan_SetLatencyMarker(HANDLE vkDevice, NV_VULKAN_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); static NvAPI_Status hkNvAPI_Vulkan_SetSleepMode(HANDLE vkDevice, NV_VULKAN_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); + static NvAPI_Status hkNvAPI_Vulkan_GetLatency(HANDLE vkDevice, NV_VULKAN_LATENCY_RESULT_PARAMS* pGetLatencyParams); VALIDATE_MEMBER_HOOK(hkNvAPI_D3D_SetSleepMode, decltype(&NvAPI_D3D_SetSleepMode)) VALIDATE_MEMBER_HOOK(hkNvAPI_D3D_Sleep, decltype(&NvAPI_D3D_Sleep)) @@ -69,6 +71,7 @@ class ReflexHooks VALIDATE_MEMBER_HOOK(hkNvAPI_D3D12_SetAsyncFrameMarker, decltype(&NvAPI_D3D12_SetAsyncFrameMarker)) VALIDATE_MEMBER_HOOK(hkNvAPI_Vulkan_SetLatencyMarker, decltype(&NvAPI_Vulkan_SetLatencyMarker)) VALIDATE_MEMBER_HOOK(hkNvAPI_Vulkan_SetSleepMode, decltype(&NvAPI_Vulkan_SetSleepMode)) + VALIDATE_MEMBER_HOOK(hkNvAPI_Vulkan_GetLatency, decltype(&NvAPI_Vulkan_GetLatency)) public: static std::optional timingData[TimingType::TimingTypeCOUNT];