From de523f7fcbbd7a4b60e9ab0474b239b02e20f0fb Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:46:49 +0200 Subject: [PATCH 01/18] Barebones antilag 2 support for dx12 --- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 20 ++++++++++++++++++++ OptiScaler/nvapi/fakenvapi/nvapi.h | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 593376d8..607cef2a 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -307,10 +307,30 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { + if (!pDev) + return Error(); + if (!al2_context.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDev->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + auto res = AMD::AntiLag2DX12::Initialize(&al2_context, device); + log(std::format("AL2 Init: {}", S_OK == res)); + } + if (pSetLatencyMarkerParams->markerType == SIMULATION_START) { + AMD::AntiLag2DX12::Update(&al2_context, true, 0); + } return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { + if (!pDevice) + return Error(); + if (!al2_context.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + auto res = AMD::AntiLag2DX12::Initialize(&al2_context, device); + log(std::format("AL2 Init: {}", S_OK == res)); + } + AMD::AntiLag2DX12::Update(&al2_context, true, 0); return Ok(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index b7828dde..664d8c93 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -11,6 +11,7 @@ #endif #include +#include "../include/ffx_antilag2_dx12.h" #include "util.h" #include "spoofInfo.h" #include "log.h" @@ -20,13 +21,14 @@ namespace nvd { static auto drsSession = reinterpret_cast(&drs); static auto drsProfile = reinterpret_cast(&drs); - static LUID luid; static UINT deviceId; static UINT vendorId; static UINT subSysId; static UINT revisionId; + static AMD::AntiLag2DX12::Context al2_context = {}; + 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); From a54910ecd8e92ea50e188810f60c1bd9a93b742b Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:52:29 +0200 Subject: [PATCH 02/18] Fix build on mingw --- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 4 ++++ OptiScaler/nvapi/fakenvapi/nvapi.h | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 607cef2a..6d0e0332 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -309,6 +309,7 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { if (!pDev) return Error(); +#if _MSC_VER if (!al2_context.m_pAntiLagAPI) { ID3D12Device* device = nullptr; HRESULT hr = pDev->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); @@ -318,12 +319,14 @@ namespace nvd { if (pSetLatencyMarkerParams->markerType == SIMULATION_START) { AMD::AntiLag2DX12::Update(&al2_context, true, 0); } +#endif return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { if (!pDevice) return Error(); +#if _MSC_VER if (!al2_context.m_pAntiLagAPI) { ID3D12Device* device = nullptr; HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); @@ -331,6 +334,7 @@ namespace nvd { log(std::format("AL2 Init: {}", S_OK == res)); } AMD::AntiLag2DX12::Update(&al2_context, true, 0); +#endif return Ok(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index 664d8c93..e51a3f39 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -11,7 +11,10 @@ #endif #include +#if _MSC_VER #include "../include/ffx_antilag2_dx12.h" +#endif + #include "util.h" #include "spoofInfo.h" #include "log.h" @@ -27,7 +30,9 @@ namespace nvd { static UINT subSysId; static UINT revisionId; +#if _MSC_VER static AMD::AntiLag2DX12::Context al2_context = {}; +#endif NvAPI_Status __cdecl NvAPI_Initialize(); NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc); From 93af3c19e42aa1f05989b7070b6e63dc1521afd4 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 6 Sep 2024 01:36:16 +0200 Subject: [PATCH 03/18] Add DX11 and antilag class --- OptiScaler/nvapi/fakenvapi/antilag.h | 43 ++++++++++++++++++++++++++++ OptiScaler/nvapi/fakenvapi/nvapi.cpp | 18 +++--------- OptiScaler/nvapi/fakenvapi/nvapi.h | 4 +-- 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 OptiScaler/nvapi/fakenvapi/antilag.h diff --git a/OptiScaler/nvapi/fakenvapi/antilag.h b/OptiScaler/nvapi/fakenvapi/antilag.h new file mode 100644 index 00000000..6e1854fd --- /dev/null +++ b/OptiScaler/nvapi/fakenvapi/antilag.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#if defined __MINGW64__ || defined __MINGW32__ +#include "../include/d3d12.h" +#else +#include +#endif + +#include "../include/ffx_antilag2_dx12.h" +#include "../include/ffx_antilag2_dx11.h" + +class AntiLag { + AMD::AntiLag2DX12::Context context_dx12 = {}; + AMD::AntiLag2DX11::Context context_dx11 = {}; + + void init_dx12(ID3D12Device *pDevice) { + auto res = AMD::AntiLag2DX12::Initialize(&context_dx12, pDevice); + } + void init_dx11() { + auto res = AMD::AntiLag2DX11::Initialize(&context_dx11); + } + +public: + void init(IUnknown *pDevice) { + if (!context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + if (hr == S_OK) { + init_dx12(device); + } else { + init_dx11(); + } + } + } + + void update() { + if (context_dx12.m_pAntiLagAPI) + AMD::AntiLag2DX12::Update(&context_dx12, true, 0); + else + AMD::AntiLag2DX11::Update(&context_dx11, true, 0); + } +}; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 6d0e0332..b6348713 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -310,14 +310,9 @@ namespace nvd { if (!pDev) return Error(); #if _MSC_VER - if (!al2_context.m_pAntiLagAPI) { - ID3D12Device* device = nullptr; - HRESULT hr = pDev->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); - auto res = AMD::AntiLag2DX12::Initialize(&al2_context, device); - log(std::format("AL2 Init: {}", S_OK == res)); - } + antilag_ctx.init(pDev); if (pSetLatencyMarkerParams->markerType == SIMULATION_START) { - AMD::AntiLag2DX12::Update(&al2_context, true, 0); + antilag_ctx.update(); } #endif return Ok(); @@ -327,13 +322,8 @@ namespace nvd { if (!pDevice) return Error(); #if _MSC_VER - if (!al2_context.m_pAntiLagAPI) { - ID3D12Device* device = nullptr; - HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); - auto res = AMD::AntiLag2DX12::Initialize(&al2_context, device); - log(std::format("AL2 Init: {}", S_OK == res)); - } - AMD::AntiLag2DX12::Update(&al2_context, true, 0); + antilag_ctx.init(pDevice); + antilag_ctx.update(); #endif return Ok(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index e51a3f39..47695ef4 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -12,7 +12,7 @@ #include #if _MSC_VER -#include "../include/ffx_antilag2_dx12.h" +#include "antilag.h" #endif #include "util.h" @@ -31,7 +31,7 @@ namespace nvd { static UINT revisionId; #if _MSC_VER - static AMD::AntiLag2DX12::Context al2_context = {}; + static AntiLag antilag_ctx; #endif NvAPI_Status __cdecl NvAPI_Initialize(); From 359a261c01fd4768c7bdfc6da3ee7cb04a5403ff Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:10:42 +0200 Subject: [PATCH 04/18] Fix Windows builds, add FPS limiter and mark extra points --- OptiScaler/nvapi/fakenvapi/antilag.h | 22 ++++++++++++++++++++-- OptiScaler/nvapi/fakenvapi/log.h | 1 + OptiScaler/nvapi/fakenvapi/main.cpp | 1 + OptiScaler/nvapi/fakenvapi/nvapi.cpp | 15 ++++++++++++++- OptiScaler/nvapi/fakenvapi/util.h | 1 + 5 files changed, 37 insertions(+), 3 deletions(-) mode change 100644 => 100755 OptiScaler/nvapi/fakenvapi/antilag.h mode change 100644 => 100755 OptiScaler/nvapi/fakenvapi/log.h mode change 100644 => 100755 OptiScaler/nvapi/fakenvapi/util.h diff --git a/OptiScaler/nvapi/fakenvapi/antilag.h b/OptiScaler/nvapi/fakenvapi/antilag.h old mode 100644 new mode 100755 index 6e1854fd..61098a66 --- a/OptiScaler/nvapi/fakenvapi/antilag.h +++ b/OptiScaler/nvapi/fakenvapi/antilag.h @@ -10,9 +10,12 @@ #include "../include/ffx_antilag2_dx12.h" #include "../include/ffx_antilag2_dx11.h" +#include "log.h" + class AntiLag { AMD::AntiLag2DX12::Context context_dx12 = {}; AMD::AntiLag2DX11::Context context_dx11 = {}; + unsigned int max_fps = 0; void init_dx12(ID3D12Device *pDevice) { auto res = AMD::AntiLag2DX12::Initialize(&context_dx12, pDevice); @@ -36,8 +39,23 @@ public: void update() { if (context_dx12.m_pAntiLagAPI) - AMD::AntiLag2DX12::Update(&context_dx12, true, 0); + AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); else - AMD::AntiLag2DX11::Update(&context_dx11, true, 0); + AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); + } + + void mark_end_of_rendering() { + if (context_dx12.m_pAntiLagAPI) + AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); + } + + void present_start(bool interpolated_frame) { + if (context_dx12.m_pAntiLagAPI) + AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated_frame); + } + + void set_fps_limit(unsigned int fps) { + log(std::format("Max fps: {}", fps)); + max_fps = fps; } }; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/log.h b/OptiScaler/nvapi/fakenvapi/log.h old mode 100644 new mode 100755 index 96465672..e447a4a8 --- a/OptiScaler/nvapi/fakenvapi/log.h +++ b/OptiScaler/nvapi/fakenvapi/log.h @@ -1,4 +1,5 @@ #pragma once +#define _CRT_SECURE_NO_WARNINGS 1 #include #include #include diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index db14ae16..e9eef93c 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -1,3 +1,4 @@ +#define _CRT_SECURE_NO_WARNINGS 1 #include #include #include diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index b6348713..febce021 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -303,16 +303,29 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { +#if _MSC_VER + if (pSetSleepModeParams->minimumIntervalUs > 0) + antilag_ctx.set_fps_limit(1000000 / pSetSleepModeParams->minimumIntervalUs); +#endif return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { if (!pDev) return Error(); + log(std::format("markerType: {}", (unsigned int)pSetLatencyMarkerParams->markerType)); #if _MSC_VER antilag_ctx.init(pDev); - if (pSetLatencyMarkerParams->markerType == SIMULATION_START) { + switch (pSetLatencyMarkerParams->markerType) { + case SIMULATION_START: antilag_ctx.update(); + break; + case RENDERSUBMIT_END: + antilag_ctx.mark_end_of_rendering(); + break; + case PRESENT_START: + antilag_ctx.present_start(false); + break; } #endif return Ok(); diff --git a/OptiScaler/nvapi/fakenvapi/util.h b/OptiScaler/nvapi/fakenvapi/util.h old mode 100644 new mode 100755 index 3f4153ca..b884f538 --- a/OptiScaler/nvapi/fakenvapi/util.h +++ b/OptiScaler/nvapi/fakenvapi/util.h @@ -1,4 +1,5 @@ #pragma once +#define _CRT_SECURE_NO_WARNINGS 1 #include "../include/nvapi.h" #include #include From b8a453eaa9e66d66109d1db970bdeba0ef4c3909 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Sat, 7 Sep 2024 01:17:29 +0200 Subject: [PATCH 05/18] Adjust update point + fix rdr2 crashing --- OptiScaler/nvapi/fakenvapi/antilag.h | 37 +++++++++++----------------- OptiScaler/nvapi/fakenvapi/main.cpp | 6 +++-- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 19 +++++++------- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/antilag.h b/OptiScaler/nvapi/fakenvapi/antilag.h index 61098a66..090bed4a 100755 --- a/OptiScaler/nvapi/fakenvapi/antilag.h +++ b/OptiScaler/nvapi/fakenvapi/antilag.h @@ -16,42 +16,33 @@ class AntiLag { AMD::AntiLag2DX12::Context context_dx12 = {}; AMD::AntiLag2DX11::Context context_dx11 = {}; unsigned int max_fps = 0; - - void init_dx12(ID3D12Device *pDevice) { - auto res = AMD::AntiLag2DX12::Initialize(&context_dx12, pDevice); - } - void init_dx11() { - auto res = AMD::AntiLag2DX11::Initialize(&context_dx11); - } + bool al_available = false; public: - void init(IUnknown *pDevice) { + bool calls_input_sample = false; + bool calls_sleep = false; + + inline HRESULT init(IUnknown *pDevice) { if (!context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { ID3D12Device* device = nullptr; HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + HRESULT init_return = S_FALSE; if (hr == S_OK) { - init_dx12(device); + init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); } else { - init_dx11(); + init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); } + al_available = init_return == S_OK; } + return 0x2137; } - void update() { + inline HRESULT update() { + if (!al_available) return S_FALSE; if (context_dx12.m_pAntiLagAPI) - AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); + return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); else - AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); - } - - void mark_end_of_rendering() { - if (context_dx12.m_pAntiLagAPI) - AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); - } - - void present_start(bool interpolated_frame) { - if (context_dx12.m_pAntiLagAPI) - AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated_frame); + return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); } void set_fps_limit(unsigned int fps) { diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index e9eef93c..066311e6 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -18,9 +18,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { auto logEnv = std::getenv("NVAPI_LOG"); + bool force_log = false; switch (fdwReason) { case DLL_PROCESS_ATTACH: - if (logEnv && *logEnv == '1') + if ((logEnv && *logEnv == '1') || force_log) prepareLogging("nvapi-dummy.log"); else prepareLogging(std::nullopt); @@ -45,7 +46,8 @@ namespace nvd { extern "C" { NvAPI_Status __cdecl placeholder() { // return Ok(); - return Error(NVAPI_NO_IMPLEMENTATION); + // return Error(NVAPI_NO_IMPLEMENTATION); + return NVAPI_NO_IMPLEMENTATION; // no logging } static std::unordered_map registry; diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index febce021..273e3696 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -57,7 +57,7 @@ namespace nvd { if (displayId == 0) { return Ok(); } - return Error(NVAPI_NVIDIA_DISPLAY_NOT_FOUND); + return Error(NVAPI_END_ENUMERATION); } NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { @@ -313,18 +313,18 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { if (!pDev) return Error(); - log(std::format("markerType: {}", (unsigned int)pSetLatencyMarkerParams->markerType)); + log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); #if _MSC_VER antilag_ctx.init(pDev); switch (pSetLatencyMarkerParams->markerType) { case SIMULATION_START: - antilag_ctx.update(); + if (antilag_ctx.calls_input_sample || antilag_ctx.calls_sleep) break; + log(std::format("AntiLag update called on simulation start with result: {}", antilag_ctx.update())); break; - case RENDERSUBMIT_END: - antilag_ctx.mark_end_of_rendering(); - break; - case PRESENT_START: - antilag_ctx.present_start(false); + case INPUT_SAMPLE: + if (antilag_ctx.calls_sleep) break; + antilag_ctx.calls_input_sample = true; + log(std::format("AntiLag update called on input sample with result: {}", antilag_ctx.update())); break; } #endif @@ -336,7 +336,8 @@ namespace nvd { return Error(); #if _MSC_VER antilag_ctx.init(pDevice); - antilag_ctx.update(); + antilag_ctx.calls_sleep = true; + log(std::format("AntiLag update called on sleep with result: {}", antilag_ctx.update())); #endif return Ok(); } From f2104d4acd7cf4814fa5475aca587f7d2a877474 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Sat, 7 Sep 2024 01:55:58 +0200 Subject: [PATCH 06/18] Build antilag2 only on 64bit --- OptiScaler/nvapi/fakenvapi/nvapi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index 47695ef4..27d1e5b9 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -11,7 +11,7 @@ #endif #include -#if _MSC_VER +#if _MSC_VER && _WIN64 #include "antilag.h" #endif @@ -30,7 +30,7 @@ namespace nvd { static UINT subSysId; static UINT revisionId; -#if _MSC_VER +#if _MSC_VER && _WIN64 static AntiLag antilag_ctx; #endif From bc1c726815a872fe6533830f6fed7db76936abfa Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Sat, 7 Sep 2024 01:58:50 +0200 Subject: [PATCH 07/18] Build antilag2 only on 64bit --- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 273e3696..50c6a588 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -303,7 +303,7 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { -#if _MSC_VER +#if _MSC_VER && _WIN64 if (pSetSleepModeParams->minimumIntervalUs > 0) antilag_ctx.set_fps_limit(1000000 / pSetSleepModeParams->minimumIntervalUs); #endif @@ -314,7 +314,7 @@ namespace nvd { if (!pDev) return Error(); log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); -#if _MSC_VER +#if _MSC_VER && _WIN64 antilag_ctx.init(pDev); switch (pSetLatencyMarkerParams->markerType) { case SIMULATION_START: @@ -334,7 +334,7 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { if (!pDevice) return Error(); -#if _MSC_VER +#if _MSC_VER && _WIN64 antilag_ctx.init(pDevice); antilag_ctx.calls_sleep = true; log(std::format("AntiLag update called on sleep with result: {}", antilag_ctx.update())); From 9a81af9b75585c567af335b9ee20f04f5912737a Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Mon, 9 Sep 2024 00:02:36 +0200 Subject: [PATCH 08/18] Add latencyflex, clean up logs, --- OptiScaler/nvapi/fakenvapi/antilag.h | 52 ---------- OptiScaler/nvapi/fakenvapi/log.cpp | 18 +++- OptiScaler/nvapi/fakenvapi/lowlatency.h | 124 ++++++++++++++++++++++++ OptiScaler/nvapi/fakenvapi/main.cpp | 7 +- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 70 ++++++++++--- OptiScaler/nvapi/fakenvapi/nvapi.h | 8 +- 6 files changed, 209 insertions(+), 70 deletions(-) delete mode 100755 OptiScaler/nvapi/fakenvapi/antilag.h create mode 100644 OptiScaler/nvapi/fakenvapi/lowlatency.h diff --git a/OptiScaler/nvapi/fakenvapi/antilag.h b/OptiScaler/nvapi/fakenvapi/antilag.h deleted file mode 100755 index 090bed4a..00000000 --- a/OptiScaler/nvapi/fakenvapi/antilag.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include -#if defined __MINGW64__ || defined __MINGW32__ -#include "../include/d3d12.h" -#else -#include -#endif - -#include "../include/ffx_antilag2_dx12.h" -#include "../include/ffx_antilag2_dx11.h" - -#include "log.h" - -class AntiLag { - AMD::AntiLag2DX12::Context context_dx12 = {}; - AMD::AntiLag2DX11::Context context_dx11 = {}; - unsigned int max_fps = 0; - bool al_available = false; - -public: - bool calls_input_sample = false; - bool calls_sleep = false; - - inline HRESULT init(IUnknown *pDevice) { - if (!context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { - ID3D12Device* device = nullptr; - HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); - HRESULT init_return = S_FALSE; - if (hr == S_OK) { - init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); - } else { - init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); - } - al_available = init_return == S_OK; - } - return 0x2137; - } - - inline HRESULT update() { - if (!al_available) return S_FALSE; - if (context_dx12.m_pAntiLagAPI) - return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); - else - return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); - } - - void set_fps_limit(unsigned int fps) { - log(std::format("Max fps: {}", fps)); - max_fps = fps; - } -}; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 254c46f1..5f88efc0 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -19,17 +19,29 @@ std::string getCurrentTimeFormatted() { return oss.str(); } +std::string extractFunctionName(const std::string& signature) { + size_t start = signature.find("nvd::"); + if (start == std::string::npos) return {}; + start += 5; + size_t end = signature.find('(', start); + if (end == std::string::npos) return {}; + + return signature.substr(start, end - start); +} + void log(const std::string& log) { - *logStream << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; + std::ostringstream oss; + oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; + *logStream << oss.str(); } NvAPI_Status Ok(const std::source_location& location) { - log(std::format("{}: {}", location.function_name(), "OK")); + log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); return NVAPI_OK; } NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { - log(std::format("{}: {}", location.function_name(), fromErrorNr(status))); + log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); return status; } diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h new file mode 100644 index 00000000..5601ec91 --- /dev/null +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -0,0 +1,124 @@ +#pragma once + +#include +#if defined __MINGW64__ || defined __MINGW32__ +#include "../include/d3d12.h" +#else +#include +#endif + +#include "../include/ffx_antilag2_dx12.h" +#include "../include/ffx_antilag2_dx11.h" + +#include "../include/latencyflex.h" + +#include "log.h" + +enum Mode { + AntiLag2, + LatencyFlex, +}; + +enum CallSpot { + SleepCall = 0, + InputSample = 1, + SimulationStart = 2 +}; + +struct LFXStats { + uint64_t latency {}; + uint64_t frameTime {}; + uint64_t target {}; +}; + +class LowLatency { + AMD::AntiLag2DX12::Context context_dx12 = {}; + AMD::AntiLag2DX11::Context context_dx11 = {}; + unsigned int max_fps = 0; + bool al_available = false; + lfx::LatencyFleX *lf; + uint64_t lfx_frame_id = 0; + + static inline uint64_t GetTimestamp() { + LARGE_INTEGER frequency; + LARGE_INTEGER counter; + + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + return static_cast(counter.QuadPart) * UINT64_C(1000000000) / static_cast(frequency.QuadPart); + } + +public: + CallSpot call_spot = SimulationStart; + Mode mode = AntiLag2; + LFXStats lfx_stats = {}; + bool fg = false; + bool active = true; + + inline HRESULT init_al2(IUnknown *pDevice) { + if (mode == AntiLag2 && !context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + HRESULT init_return = S_FALSE; + if (hr == S_OK) { + init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); + } else { + init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); + } + al_available = init_return == S_OK; + } + return 0x2137; + } + + inline HRESULT update() { + if (!active) return S_OK; + + if (!fg && al_available) mode = AntiLag2; + else mode = LatencyFlex; + + log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); + log(std::format("FG status: {}", fg ? "enabled" : "disabled")); + + if (mode == AntiLag2) { + lf->Reset(); + if (context_dx12.m_pAntiLagAPI) + return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); + else + return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); + } else if (mode == LatencyFlex) { + uint64_t currentTimestamp = GetTimestamp(); + lf->target_frame_time = max_fps > 0 ? 1000000000U / max_fps : 0; + if (lfx_frame_id == 0) { + lfx_stats.target = lf->GetWaitTarget(lfx_frame_id); + currentTimestamp -= 31526756; + lf->BeginFrame(lfx_frame_id, lfx_stats.target, currentTimestamp); + } + + lf->EndFrame(lfx_frame_id, currentTimestamp, &lfx_stats.latency, &lfx_stats.frameTime); + log(std::format("LFX latency: {}", lfx_stats.latency)); + log(std::format("LFX frameTime: {}", lfx_stats.frameTime)); + lfx_frame_id++; + lfx_stats.target = lf->GetWaitTarget(lfx_frame_id); + + auto diff = lfx_stats.target - currentTimestamp; + if (lfx_stats.target > 0 && lfx_stats.target > currentTimestamp) { + //if (lfx_frame_id > 100) { + std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); + //} + } + + lf->BeginFrame(lfx_frame_id, lfx_stats.target, lfx_stats.target > currentTimestamp && lfx_frame_id >= 0 ? lfx_stats.target : currentTimestamp); + return S_OK; + } + return S_FALSE; + } + + void set_fps_limit(unsigned int fps) { + log(std::format("Max fps: {}", fps)); + max_fps = fps; + } + + void init_lfx() { + lf = new lfx::LatencyFleX(); + } +}; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index 066311e6..49dce31b 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -18,7 +18,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { auto logEnv = std::getenv("NVAPI_LOG"); - bool force_log = false; + bool force_log = true; switch (fdwReason) { case DLL_PROCESS_ATTACH: if ((logEnv && *logEnv == '1') || force_log) @@ -39,7 +39,8 @@ NVAPI_INTERFACE_TABLE additional_interface_table[] = { { "NvAPI_Diag_ReportCallStart", 0x33c7358c }, { "NvAPI_Diag_ReportCallReturn", 0x593e8644 }, { "MISC_unknown", 0xe9b009b9 }, - { "MISC_vulkan", 0x17d13d6 } + { "MISC_vulkan", 0x17d13d6 }, + { "Dummy_GetLatency", 0x21372137 } }; namespace nvd { @@ -110,6 +111,7 @@ namespace nvd { 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) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_EndUAVOverlap) @@ -129,6 +131,7 @@ namespace nvd { INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unload) INSERT_AND_RETURN_WHEN_EQUALS(MISC_unknown) INSERT_AND_RETURN_WHEN_EQUALS(MISC_vulkan) + INSERT_AND_RETURN_WHEN_EQUALS(Dummy_GetLatency) log(std::format("{}: not implemented, placeholder given", it->func)); return registry.insert({ id, (void*)placeholder }).first->second; diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 50c6a588..cbee0a18 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -33,6 +33,8 @@ namespace nvd { pAdapter->Release(); pFactory->Release(); + lowlatency_ctx.init_lfx(); + return Ok(); } @@ -303,9 +305,10 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { + unsigned int max_fps = pSetSleepModeParams->minimumIntervalUs > 0 ? 1000000 / pSetSleepModeParams->minimumIntervalUs : 0; #if _MSC_VER && _WIN64 - if (pSetSleepModeParams->minimumIntervalUs > 0) - antilag_ctx.set_fps_limit(1000000 / pSetSleepModeParams->minimumIntervalUs); + lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; // untested + lowlatency_ctx.set_fps_limit(max_fps); #endif return Ok(); } @@ -315,16 +318,16 @@ namespace nvd { return Error(); log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); #if _MSC_VER && _WIN64 - antilag_ctx.init(pDev); + lowlatency_ctx.init_al2(pDev); switch (pSetLatencyMarkerParams->markerType) { case SIMULATION_START: - if (antilag_ctx.calls_input_sample || antilag_ctx.calls_sleep) break; - log(std::format("AntiLag update called on simulation start with result: {}", antilag_ctx.update())); + if (lowlatency_ctx.call_spot != SimulationStart) break; + log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); break; case INPUT_SAMPLE: - if (antilag_ctx.calls_sleep) break; - antilag_ctx.calls_input_sample = true; - log(std::format("AntiLag update called on input sample with result: {}", antilag_ctx.update())); + if (lowlatency_ctx.call_spot == SleepCall) break; + lowlatency_ctx.call_spot = InputSample; + log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); break; } #endif @@ -335,13 +338,24 @@ namespace nvd { if (!pDevice) return Error(); #if _MSC_VER && _WIN64 - antilag_ctx.init(pDevice); - antilag_ctx.calls_sleep = true; - log(std::format("AntiLag update called on sleep with result: {}", antilag_ctx.update())); + lowlatency_ctx.init_al2(pDevice); + lowlatency_ctx.call_spot = SleepCall; + log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); #endif return Ok(); } + NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { + log("SetReflexSync"); + log(std::format("\tdisable: {}", (unsigned long)pSetReflexSyncParams->bDisable)); + log(std::format("\tenable: {}", (unsigned long)pSetReflexSyncParams->bEnable)); + log(std::format("\ttimeInQueueUs: {}", (signed long)pSetReflexSyncParams->timeInQueueUs)); + log(std::format("\ttimeInQueueUsTarget: {}", (unsigned long)pSetReflexSyncParams->timeInQueueUsTarget)); + log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->vblankIntervalUs)); + log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->version)); + return Ok(); + } + NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { *pSupported = true; return Ok(); @@ -504,6 +518,27 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { +#if _MSC_VER && _WIN64 + if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { + constexpr unsigned int history_size = 10; + static NvU64 counter = 0; + static NvU64 previous_frame_ids[history_size] = {}; + + previous_frame_ids[counter%history_size] = pSetAsyncFrameMarkerParams->frameID; + counter++; + + std::unordered_set seen; + int repeat_count = 0; + for (const int& frame_id : previous_frame_ids) { + if (seen.contains(frame_id)) repeat_count++; + else seen.insert(frame_id); + } + + if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; + else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; + } +#endif + log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); return Ok(); } @@ -542,4 +577,17 @@ namespace nvd { NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown) { return Ok(); } + + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime) { + if (!call_spot || !waitTarget || !latency || !frameTime) return Error(NVAPI_INVALID_POINTER); + + if (lowlatency_ctx.mode != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); + *call_spot = (uint64_t)lowlatency_ctx.call_spot; + + *waitTarget = lowlatency_ctx.lfx_stats.target; + *latency = lowlatency_ctx.lfx_stats.latency; + *frameTime = lowlatency_ctx.lfx_stats.frameTime; + + return Ok(); + } } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index 27d1e5b9..652d5159 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -1,6 +1,8 @@ #pragma once #include #include +#include +#include #include #include @@ -12,7 +14,7 @@ #include #if _MSC_VER && _WIN64 -#include "antilag.h" +#include "lowlatency.h" #endif #include "util.h" @@ -31,7 +33,7 @@ namespace nvd { static UINT revisionId; #if _MSC_VER && _WIN64 - static AntiLag antilag_ctx; + static LowLatency lowlatency_ctx; #endif NvAPI_Status __cdecl NvAPI_Initialize(); @@ -70,6 +72,7 @@ namespace nvd { 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); NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext); @@ -89,4 +92,5 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_Unload(); NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk); NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown); + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime); } \ No newline at end of file From 15575a83e2811555d11b8c38f743d4ae92b2867f Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Mon, 9 Sep 2024 00:06:19 +0200 Subject: [PATCH 09/18] Add AL2 FG support, reset LatencyFlex logic when needed --- OptiScaler/nvapi/fakenvapi/log.cpp | 126 +-- OptiScaler/nvapi/fakenvapi/lowlatency.h | 276 +++--- OptiScaler/nvapi/fakenvapi/main.cpp | 2 +- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 1197 ++++++++++++----------- 4 files changed, 822 insertions(+), 779 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 5f88efc0..933da4a1 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -1,64 +1,64 @@ -#include "log.h" - -std::ostream null(nullptr); -std::ostream* logStream = &null; -std::ofstream fileStream; - -std::string getCurrentTimeFormatted() { - auto now = std::chrono::system_clock::now(); - auto now_t = std::chrono::system_clock::to_time_t(now); - auto now_tm = *std::localtime(&now_t); - auto now_duration = now - std::chrono::system_clock::from_time_t(std::mktime(&now_tm)); - auto now_us = std::chrono::duration_cast(now_duration); - std::ostringstream oss; - oss << std::setfill('0') << std::setw(2) << now_tm.tm_hour << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_min << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_sec << "." - << std::setfill('0') << std::setw(6) << now_us.count(); - - return oss.str(); -} - -std::string extractFunctionName(const std::string& signature) { - size_t start = signature.find("nvd::"); - if (start == std::string::npos) return {}; - start += 5; - size_t end = signature.find('(', start); - if (end == std::string::npos) return {}; - - return signature.substr(start, end - start); -} - -void log(const std::string& log) { - std::ostringstream oss; - oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; - *logStream << oss.str(); -} - -NvAPI_Status Ok(const std::source_location& location) { - log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); - return NVAPI_OK; -} - -NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { - log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); - return status; -} - -void prepareLogging(std::optional fileName) { - if (fileName.has_value()) { - fileStream.open(fileName.value(), std::ios_base::out | std::ios_base::app); - if (fileStream.is_open()) { - logStream = &fileStream; - return; - } - else { - std::cerr << "Failed to open log file: " << fileName.value() << std::endl; - } - } - // logStream = &std::cout; -} - -void closeLogging() { - fileStream.close(); +#include "log.h" + +std::ostream null(nullptr); +std::ostream* logStream = &null; +std::ofstream fileStream; + +inline std::string getCurrentTimeFormatted() { + auto now = std::chrono::system_clock::now(); + auto now_t = std::chrono::system_clock::to_time_t(now); + auto now_tm = *std::localtime(&now_t); + auto now_duration = now - std::chrono::system_clock::from_time_t(std::mktime(&now_tm)); + auto now_us = std::chrono::duration_cast(now_duration); + std::ostringstream oss; + oss << std::setfill('0') << std::setw(2) << now_tm.tm_hour << ":" + << std::setfill('0') << std::setw(2) << now_tm.tm_min << ":" + << std::setfill('0') << std::setw(2) << now_tm.tm_sec << "." + << std::setfill('0') << std::setw(6) << now_us.count(); + + return oss.str(); +} + +inline std::string extractFunctionName(const std::string& signature) { + size_t start = signature.find("nvd::"); + if (start == std::string::npos) return {}; + start += 5; + size_t end = signature.find('(', start); + if (end == std::string::npos) return {}; + + return signature.substr(start, end - start); +} + +inline void log(const std::string& log) { + std::ostringstream oss; + oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; + *logStream << oss.str(); +} + +NvAPI_Status Ok(const std::source_location& location) { + // log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); + return NVAPI_OK; +} + +NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { + log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); + return status; +} + +void prepareLogging(std::optional fileName) { + if (fileName.has_value()) { + fileStream.open(fileName.value(), std::ios_base::out | std::ios_base::app); + if (fileStream.is_open()) { + logStream = &fileStream; + return; + } + else { + std::cerr << "Failed to open log file: " << fileName.value() << std::endl; + } + } + // logStream = &std::cout; +} + +void closeLogging() { + fileStream.close(); } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index 5601ec91..3673bb7b 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -1,124 +1,154 @@ -#pragma once - -#include -#if defined __MINGW64__ || defined __MINGW32__ -#include "../include/d3d12.h" -#else -#include -#endif - -#include "../include/ffx_antilag2_dx12.h" -#include "../include/ffx_antilag2_dx11.h" - -#include "../include/latencyflex.h" - -#include "log.h" - -enum Mode { - AntiLag2, - LatencyFlex, -}; - -enum CallSpot { - SleepCall = 0, - InputSample = 1, - SimulationStart = 2 -}; - -struct LFXStats { - uint64_t latency {}; - uint64_t frameTime {}; - uint64_t target {}; -}; - -class LowLatency { - AMD::AntiLag2DX12::Context context_dx12 = {}; - AMD::AntiLag2DX11::Context context_dx11 = {}; - unsigned int max_fps = 0; - bool al_available = false; - lfx::LatencyFleX *lf; - uint64_t lfx_frame_id = 0; - - static inline uint64_t GetTimestamp() { - LARGE_INTEGER frequency; - LARGE_INTEGER counter; - - QueryPerformanceFrequency(&frequency); - QueryPerformanceCounter(&counter); - return static_cast(counter.QuadPart) * UINT64_C(1000000000) / static_cast(frequency.QuadPart); - } - -public: - CallSpot call_spot = SimulationStart; - Mode mode = AntiLag2; - LFXStats lfx_stats = {}; - bool fg = false; - bool active = true; - - inline HRESULT init_al2(IUnknown *pDevice) { - if (mode == AntiLag2 && !context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { - ID3D12Device* device = nullptr; - HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); - HRESULT init_return = S_FALSE; - if (hr == S_OK) { - init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); - } else { - init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); - } - al_available = init_return == S_OK; - } - return 0x2137; - } - - inline HRESULT update() { - if (!active) return S_OK; - - if (!fg && al_available) mode = AntiLag2; - else mode = LatencyFlex; - - log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); - log(std::format("FG status: {}", fg ? "enabled" : "disabled")); - - if (mode == AntiLag2) { - lf->Reset(); - if (context_dx12.m_pAntiLagAPI) - return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); - else - return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); - } else if (mode == LatencyFlex) { - uint64_t currentTimestamp = GetTimestamp(); - lf->target_frame_time = max_fps > 0 ? 1000000000U / max_fps : 0; - if (lfx_frame_id == 0) { - lfx_stats.target = lf->GetWaitTarget(lfx_frame_id); - currentTimestamp -= 31526756; - lf->BeginFrame(lfx_frame_id, lfx_stats.target, currentTimestamp); - } - - lf->EndFrame(lfx_frame_id, currentTimestamp, &lfx_stats.latency, &lfx_stats.frameTime); - log(std::format("LFX latency: {}", lfx_stats.latency)); - log(std::format("LFX frameTime: {}", lfx_stats.frameTime)); - lfx_frame_id++; - lfx_stats.target = lf->GetWaitTarget(lfx_frame_id); - - auto diff = lfx_stats.target - currentTimestamp; - if (lfx_stats.target > 0 && lfx_stats.target > currentTimestamp) { - //if (lfx_frame_id > 100) { - std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); - //} - } - - lf->BeginFrame(lfx_frame_id, lfx_stats.target, lfx_stats.target > currentTimestamp && lfx_frame_id >= 0 ? lfx_stats.target : currentTimestamp); - return S_OK; - } - return S_FALSE; - } - - void set_fps_limit(unsigned int fps) { - log(std::format("Max fps: {}", fps)); - max_fps = fps; - } - - void init_lfx() { - lf = new lfx::LatencyFleX(); - } +#pragma once + +#include +#if defined __MINGW64__ || defined __MINGW32__ +#include "../include/d3d12.h" +#else +#include +#endif + +#include "../include/ffx_antilag2_dx12.h" +#include "../include/ffx_antilag2_dx11.h" + +#include "../include/latencyflex.h" + +#include "log.h" + +enum Mode { + AntiLag2, + LatencyFlex, +}; + +enum CallSpot { + SleepCall = 0, + InputSample = 1, + SimulationStart = 2 +}; + +struct LFXStats { + uint64_t latency = {}; + uint64_t frameTime = {}; + uint64_t target = {}; + uint64_t lfx_frame_id = {}; + bool needs_reset = false; + +}; + +class LowLatency { + AMD::AntiLag2DX12::Context context_dx12 = {}; + AMD::AntiLag2DX11::Context context_dx11 = {}; + unsigned long min_interval_us = 0; + bool al_available = false; + lfx::LatencyFleX *lf; + + static inline uint64_t GetTimestamp() { + LARGE_INTEGER frequency; + LARGE_INTEGER counter; + + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + return static_cast(counter.QuadPart) * UINT64_C(1000000000) / static_cast(frequency.QuadPart); + } + +public: + CallSpot call_spot = SimulationStart; + Mode mode = AntiLag2; + LFXStats lfx_stats = {}; + bool fg = false; + bool active = true; + + inline HRESULT init_al2(IUnknown *pDevice) { + if (mode == AntiLag2 && !context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + HRESULT init_return = S_FALSE; + if (hr == S_OK) { + init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); + } else { + init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); + } + al_available = init_return == S_OK; + } + return 0x2137; + } + + inline HRESULT update() { + if (!active) return S_OK; + + if (al_available) mode = AntiLag2; + else mode = LatencyFlex; + + log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); + log(std::format("FG status: {}", fg ? "enabled" : "disabled")); + + if (mode == AntiLag2) { + if (lfx_stats.lfx_frame_id != 1) lfx_stats.needs_reset = true; + int max_fps = min_interval_us > 0 ? 1000000 / min_interval_us : 0; + if (context_dx12.m_pAntiLagAPI) + return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); + else + return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); + } else if (mode == LatencyFlex) { + if (lfx_stats.needs_reset) { + log("LFX Reset"); + lfx_stats.lfx_frame_id = 1; + lfx_stats.needs_reset = false; + lf->Reset(); + } + uint64_t currentTimestamp = GetTimestamp(); + uint64_t timestamp; + + // Set FPS Limiter + lf->target_frame_time = 1000 * min_interval_us; + + lf->EndFrame(lfx_stats.lfx_frame_id, currentTimestamp, &lfx_stats.latency, &lfx_stats.frameTime); + // log(std::format("LFX latency: {}", lfx_stats.latency)); + // log(std::format("LFX frameTime: {}", lfx_stats.frameTime)); + lfx_stats.lfx_frame_id++; + lfx_stats.target = lf->GetWaitTarget(lfx_stats.lfx_frame_id); + + auto diff = lfx_stats.target - currentTimestamp; + if (lfx_stats.target > currentTimestamp) { + static uint64_t timeout_events = 0; + uint64_t timeout_timestamp = currentTimestamp + 50000000ULL; + if (lfx_stats.target > timeout_timestamp) { + timestamp = timeout_timestamp; + timeout_events++; + if (timeout_events > 5) lfx_stats.needs_reset = true; + } else { + timestamp = lfx_stats.target; + timeout_events = 0; + } + std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); + } else { + timestamp = currentTimestamp; + } + + lf->BeginFrame(lfx_stats.lfx_frame_id, lfx_stats.target, timestamp); + return S_OK; + } + return S_FALSE; + } + + inline HRESULT set_fg_type(bool interpolated) { + return AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated); + } + + inline HRESULT mark_end_of_rendering() { + return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); + } + + inline void unload() { + if (context_dx12.m_pAntiLagAPI) AMD::AntiLag2DX12::DeInitialize(&context_dx12); + if (context_dx11.m_pAntiLagAPI) AMD::AntiLag2DX11::DeInitialize(&context_dx11); + } + + void set_min_interval_us(unsigned long interval_us) { + log(std::format("Max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0)); + min_interval_us = interval_us; + } + + void init_lfx() { + lf = new lfx::LatencyFleX(); + } }; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index 49dce31b..b5255cde 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -18,7 +18,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { auto logEnv = std::getenv("NVAPI_LOG"); - bool force_log = true; + bool force_log = false; switch (fdwReason) { case DLL_PROCESS_ATTACH: if ((logEnv && *logEnv == '1') || force_log) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index cbee0a18..6e5fe71b 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -1,593 +1,606 @@ -#include "nvapi.h" -#include - -namespace nvd { - NvAPI_Status __cdecl NvAPI_Initialize() { - IDXGIFactory1* pFactory = nullptr; - if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { - log("Failed to create DXGI Factory"); - return Error(); - } - - IDXGIAdapter1* pAdapter = nullptr; - if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { - log("Failed to enumerate adapters"); - pFactory->Release(); - return Error(); - } - - DXGI_ADAPTER_DESC1 adapterDesc; - if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { - log("Failed to get adapter description"); - pAdapter->Release(); - pFactory->Release(); - return Error(); - } - - luid = adapterDesc.AdapterLuid; - deviceId = adapterDesc.DeviceId; - vendorId = adapterDesc.VendorId; - subSysId = adapterDesc.SubSysId; - revisionId = adapterDesc.Revision; - - pAdapter->Release(); - pFactory->Release(); - - lowlatency_ctx.init_lfx(); - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc) { - tonvss(desc, "NvAPI dummy"); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count) { - handles[0] = nullptr; - *count = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count) { - handles[0] = nullptr; - *count = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle) { - if (displayId == 0) { - return Ok(); - } - return Error(NVAPI_END_ENUMERATION); - } - - NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { - *logicalHandle = nullptr; - return Ok(); - } - - - NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId) { - *pGpuId = 42; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU) { - *pPhysicalGPU = nullptr; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32* pGpuCount) { - nvGPUHandle[0] = nullptr; - *pGpuCount = 1; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { - std::string error = fromErrorNr(status); - log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); - tonvss(szMsg, error); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo) { - auto pComputeTopoV1 = reinterpret_cast(pComputeTopo); - pComputeTopoV1->gpuCount = 1; - pComputeTopoV1->computeGpus[0].hPhysicalGpu = nullptr; - pComputeTopoV1->computeGpus[0].flags = NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_CAPABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_ENABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_RECOMMENDED; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags) { - *displayCount = 0; // no displays connected, may cause issues - // NVAPI_NVIDIA_DISPLAY_NOT_FOUND could be considered - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { - archInfo->architecture = spoof::arch; - archInfo->architecture_id = spoof::arch; - archInfo->implementation = spoof::implementation; - archInfo->implementation_id = spoof::implementation; - archInfo->revision = spoof::revision; - archInfo->revision_id = spoof::revision; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData) { - memcpy(logicalGpuData->pOSAdapterId, &luid, sizeof(luid)); - logicalGpuData->physicalGpuHandles[0] = nullptr; - logicalGpuData->physicalGpuCount = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId) { - *pDeviceId = (deviceId << 16) | vendorId; - *pSubSystemId = subSysId; - *pRevisionId = revisionId; - *pExtDeviceId = deviceId; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { - tonvss(szName, spoof::fullGPUName); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount) { - *pCount = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs) { - if (pClkFreqs == nullptr) - return Error(NVAPI_INVALID_ARGUMENT); - - if (pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_1 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_2 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_3) - return Error(NVAPI_INCOMPATIBLE_STRUCT_VERSION); - - if (pClkFreqs->ClockType != static_cast(NV_GPU_CLOCK_FREQUENCIES_CURRENT_FREQ)) { - return Error(NVAPI_NOT_SUPPORTED); - } - - // Reset all clock data for all domains - for (auto& domain : pClkFreqs->domain) { - domain.bIsPresent = 0; - domain.frequency = 0; - } - - unsigned int clock = 1600; - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].frequency = (clock * 1000); - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].frequency = (clock * 1000); - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].frequency = (clock * 1000); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) { - memcpy(pOSAdapterId, &luid, sizeof(luid)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo) { - if (!pPstatesInfo) - return Error(); - - // Initialize the structure with mock data - pPstatesInfo->version = NV_GPU_PERF_PSTATES20_INFO_VER; - pPstatesInfo->numPstates = 2; // Example: 2 P-states - pPstatesInfo->numClocks = 3; - pPstatesInfo->numBaseVoltages = 1; - pPstatesInfo->ov.numVoltages = 0; - - // Fill mock data for P-state 0 - pPstatesInfo->pstates[0].pstateId = NVAPI_GPU_PERF_PSTATE_P0; - pPstatesInfo->pstates[0].bIsEditable = false; - pPstatesInfo->pstates[0].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].baseVoltages[0].volt_uV = 1000000; // 1V - pPstatesInfo->pstates[0].baseVoltages[0].bIsEditable = false; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.value = 1000; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.min = 0; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.max = 0; - - // Fill mock data for P-state 1 - pPstatesInfo->pstates[1].pstateId = NVAPI_GPU_PERF_PSTATE_P1; - pPstatesInfo->pstates[1].bIsEditable = false; - pPstatesInfo->pstates[1].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].baseVoltages[0].volt_uV = 1000000; // 1V - pPstatesInfo->pstates[1].baseVoltages[0].bIsEditable = false; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.value = 1000; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.min = 0; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.max = 0; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { - *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { - *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected) { - for (int i = 0; i < NV_MOSAIC_MAX_DISPLAYS; i++) { - viewports[i].top = 0; - viewports[i].left = 0; - viewports[i].right = 0; - viewports[i].bottom = 0; - } - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { - spoof::driverInfo(driverInfo); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { - memset(pDriverVersion, 0, sizeof(NvU32)); - memcpy(pDriverVersion, &spoof::driverVersion, sizeof(NvU32)); - // *pDriverVersion = spoof::driverVersion; - tonvss(szBuildBranchString, spoof::buildBranch); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId) { - *hPhysicalGpu = nullptr; - *outputId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle) { - *pHandle = (NVDX_ObjectHandle)pResource; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { - return Error(NVAPI_NO_IMPLEMENTATION); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { - unsigned int max_fps = pSetSleepModeParams->minimumIntervalUs > 0 ? 1000000 / pSetSleepModeParams->minimumIntervalUs : 0; -#if _MSC_VER && _WIN64 - lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; // untested - lowlatency_ctx.set_fps_limit(max_fps); -#endif - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { - if (!pDev) - return Error(); - log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); -#if _MSC_VER && _WIN64 - lowlatency_ctx.init_al2(pDev); - switch (pSetLatencyMarkerParams->markerType) { - case SIMULATION_START: - if (lowlatency_ctx.call_spot != SimulationStart) break; - log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); - break; - case INPUT_SAMPLE: - if (lowlatency_ctx.call_spot == SleepCall) break; - lowlatency_ctx.call_spot = InputSample; - log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); - break; - } -#endif - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { - if (!pDevice) - return Error(); -#if _MSC_VER && _WIN64 - lowlatency_ctx.init_al2(pDevice); - lowlatency_ctx.call_spot = SleepCall; - log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); -#endif - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { - log("SetReflexSync"); - log(std::format("\tdisable: {}", (unsigned long)pSetReflexSyncParams->bDisable)); - log(std::format("\tenable: {}", (unsigned long)pSetReflexSyncParams->bEnable)); - log(std::format("\ttimeInQueueUs: {}", (signed long)pSetReflexSyncParams->timeInQueueUs)); - log(std::format("\ttimeInQueueUsTarget: {}", (unsigned long)pSetReflexSyncParams->timeInQueueUsTarget)); - log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->vblankIntervalUs)); - log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->version)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { - *pSupported = true; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize) { - if (pData == nullptr) - return Error(NVAPI_INVALID_POINTER); - - switch (type) { - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS)) - return Error(NVAPI_INVALID_ARGUMENT); - - // let's hope that NvAPI_D3D12_IsNvShaderExtnOpCodeSupported returning false is enough to discourage games from attempting to use Shader Execution Reordering - *(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS*)pData = NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAP_NONE; - break; - - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS)) - return Error(NVAPI_INVALID_POINTER); - - *(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_NONE; - break; - - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS)) - return Error(NVAPI_INVALID_POINTER); - - *(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE; - break; - - default: - return Error(NVAPI_INVALID_POINTER); - } - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { - // VKD3D-Proton does not know any NVIDIA intrinsics - *pSupported = false; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread() { - return Ok(); - } - - static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { - d3dDesc->Type = nvDesc->type; - // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed - d3dDesc->Flags = static_cast(nvDesc->flags & 0x3f); - d3dDesc->NumDescs = nvDesc->numDescs; - d3dDesc->DescsLayout = nvDesc->descsLayout; - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - d3dDesc->InstanceDescs = nvDesc->instanceDescs; - return true; - } - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) { - d3dDesc->ppGeometryDescs = reinterpret_cast(nvDesc->ppGeometryDescs); - return true; - } - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY) { - geometryDescs.resize(d3dDesc->NumDescs); - - for (unsigned i = 0; i < d3dDesc->NumDescs; ++i) { - auto& d3dGeoDesc = geometryDescs[i]; - auto& nvGeoDesc = *reinterpret_cast(reinterpret_cast(nvDesc->pGeometryDescs) + (i * nvDesc->geometryDescStrideInBytes)); - - d3dGeoDesc.Flags = nvGeoDesc.flags; - - switch (nvGeoDesc.type) { - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES_EX: - d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - d3dGeoDesc.Triangles = nvGeoDesc.triangles; - break; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS_EX: - d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; - d3dGeoDesc.AABBs = nvGeoDesc.aabbs; - break; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this - log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); - return false; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this - log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); - return false; - default: - log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); - return false; - } - } - - d3dDesc->pGeometryDescs = geometryDescs.data(); - return true; - } - - return false; - } - - NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams) { - std::vector geometryDescs{}; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS desc{}; - - if (!ConvertBuildRaytracingAccelerationStructureInputs(pParams->pDesc, geometryDescs, &desc)) - return Error(NVAPI_INVALID_ARGUMENT); - - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&desc, pParams->pInfo); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams) { - std::vector geometryDescs{}; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = { - .DestAccelerationStructureData = pParams->pDesc->destAccelerationStructureData, - .Inputs = {}, - .SourceAccelerationStructureData = pParams->pDesc->sourceAccelerationStructureData, - .ScratchAccelerationStructureData = pParams->pDesc->scratchAccelerationStructureData, - }; - - if (!ConvertBuildRaytracingAccelerationStructureInputs(&pParams->pDesc->inputs, geometryDescs, &desc.Inputs)) - return Error(NVAPI_INVALID_ARGUMENT); - - pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { -#if _MSC_VER && _WIN64 - if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { - constexpr unsigned int history_size = 10; - static NvU64 counter = 0; - static NvU64 previous_frame_ids[history_size] = {}; - - previous_frame_ids[counter%history_size] = pSetAsyncFrameMarkerParams->frameID; - counter++; - - std::unordered_set seen; - int repeat_count = 0; - for (const int& frame_id : previous_frame_ids) { - if (seen.contains(frame_id)) repeat_count++; - else seen.insert(frame_id); - } - - if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; - else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; - } -#endif - log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session) { - *session = drsSession; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { - *profile = drsProfile; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { - log(std::format("Missing setting: {}", settingId)); - return Error(NVAPI_SETTING_NOT_FOUND); - } - - NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Unload() { - return Ok(); - } - - NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk) { - std::fill(pMiscUnk, pMiscUnk + 4, 0x1); - return Ok(); - } - - NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown) { - return Ok(); - } - - NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime) { - if (!call_spot || !waitTarget || !latency || !frameTime) return Error(NVAPI_INVALID_POINTER); - - if (lowlatency_ctx.mode != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); - *call_spot = (uint64_t)lowlatency_ctx.call_spot; - - *waitTarget = lowlatency_ctx.lfx_stats.target; - *latency = lowlatency_ctx.lfx_stats.latency; - *frameTime = lowlatency_ctx.lfx_stats.frameTime; - - return Ok(); - } +#include "nvapi.h" +#include + +namespace nvd { + NvAPI_Status __cdecl NvAPI_Initialize() { + IDXGIFactory1* pFactory = nullptr; + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { + log("Failed to create DXGI Factory"); + return Error(); + } + + IDXGIAdapter1* pAdapter = nullptr; + if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { + log("Failed to enumerate adapters"); + pFactory->Release(); + return Error(); + } + + DXGI_ADAPTER_DESC1 adapterDesc; + if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { + log("Failed to get adapter description"); + pAdapter->Release(); + pFactory->Release(); + return Error(); + } + + luid = adapterDesc.AdapterLuid; + deviceId = adapterDesc.DeviceId; + vendorId = adapterDesc.VendorId; + subSysId = adapterDesc.SubSysId; + revisionId = adapterDesc.Revision; + + pAdapter->Release(); + pFactory->Release(); + + lowlatency_ctx.init_lfx(); + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc) { + tonvss(desc, "NvAPI dummy"); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count) { + handles[0] = nullptr; + *count = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count) { + handles[0] = nullptr; + *count = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle) { + if (displayId == 0) { + return Ok(); + } + return Error(NVAPI_END_ENUMERATION); + } + + NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { + *logicalHandle = nullptr; + return Ok(); + } + + + NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId) { + *pGpuId = 42; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU) { + *pPhysicalGPU = nullptr; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32* pGpuCount) { + nvGPUHandle[0] = nullptr; + *pGpuCount = 1; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { + std::string error = fromErrorNr(status); + log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); + tonvss(szMsg, error); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo) { + auto pComputeTopoV1 = reinterpret_cast(pComputeTopo); + pComputeTopoV1->gpuCount = 1; + pComputeTopoV1->computeGpus[0].hPhysicalGpu = nullptr; + pComputeTopoV1->computeGpus[0].flags = NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_CAPABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_ENABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_RECOMMENDED; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags) { + *displayCount = 0; // no displays connected, may cause issues + // NVAPI_NVIDIA_DISPLAY_NOT_FOUND could be considered + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { + archInfo->architecture = spoof::arch; + archInfo->architecture_id = spoof::arch; + archInfo->implementation = spoof::implementation; + archInfo->implementation_id = spoof::implementation; + archInfo->revision = spoof::revision; + archInfo->revision_id = spoof::revision; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData) { + memcpy(logicalGpuData->pOSAdapterId, &luid, sizeof(luid)); + logicalGpuData->physicalGpuHandles[0] = nullptr; + logicalGpuData->physicalGpuCount = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId) { + *pDeviceId = (deviceId << 16) | vendorId; + *pSubSystemId = subSysId; + *pRevisionId = revisionId; + *pExtDeviceId = deviceId; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { + tonvss(szName, spoof::fullGPUName); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount) { + *pCount = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs) { + if (pClkFreqs == nullptr) + return Error(NVAPI_INVALID_ARGUMENT); + + if (pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_1 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_2 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_3) + return Error(NVAPI_INCOMPATIBLE_STRUCT_VERSION); + + if (pClkFreqs->ClockType != static_cast(NV_GPU_CLOCK_FREQUENCIES_CURRENT_FREQ)) { + return Error(NVAPI_NOT_SUPPORTED); + } + + // Reset all clock data for all domains + for (auto& domain : pClkFreqs->domain) { + domain.bIsPresent = 0; + domain.frequency = 0; + } + + unsigned int clock = 1600; + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].frequency = (clock * 1000); + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].frequency = (clock * 1000); + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].frequency = (clock * 1000); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) { + memcpy(pOSAdapterId, &luid, sizeof(luid)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo) { + if (!pPstatesInfo) + return Error(); + + // Initialize the structure with mock data + pPstatesInfo->version = NV_GPU_PERF_PSTATES20_INFO_VER; + pPstatesInfo->numPstates = 2; // Example: 2 P-states + pPstatesInfo->numClocks = 3; + pPstatesInfo->numBaseVoltages = 1; + pPstatesInfo->ov.numVoltages = 0; + + // Fill mock data for P-state 0 + pPstatesInfo->pstates[0].pstateId = NVAPI_GPU_PERF_PSTATE_P0; + pPstatesInfo->pstates[0].bIsEditable = false; + pPstatesInfo->pstates[0].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].baseVoltages[0].volt_uV = 1000000; // 1V + pPstatesInfo->pstates[0].baseVoltages[0].bIsEditable = false; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.value = 1000; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.min = 0; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.max = 0; + + // Fill mock data for P-state 1 + pPstatesInfo->pstates[1].pstateId = NVAPI_GPU_PERF_PSTATE_P1; + pPstatesInfo->pstates[1].bIsEditable = false; + pPstatesInfo->pstates[1].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].baseVoltages[0].volt_uV = 1000000; // 1V + pPstatesInfo->pstates[1].baseVoltages[0].bIsEditable = false; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.value = 1000; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.min = 0; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.max = 0; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { + *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { + *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected) { + for (int i = 0; i < NV_MOSAIC_MAX_DISPLAYS; i++) { + viewports[i].top = 0; + viewports[i].left = 0; + viewports[i].right = 0; + viewports[i].bottom = 0; + } + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { + spoof::driverInfo(driverInfo); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { + memset(pDriverVersion, 0, sizeof(NvU32)); + memcpy(pDriverVersion, &spoof::driverVersion, sizeof(NvU32)); + // *pDriverVersion = spoof::driverVersion; + tonvss(szBuildBranchString, spoof::buildBranch); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId) { + *hPhysicalGpu = nullptr; + *outputId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle) { + *pHandle = (NVDX_ObjectHandle)pResource; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { + return Error(NVAPI_NO_IMPLEMENTATION); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { +#if _MSC_VER && _WIN64 + lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; // untested + lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); +#endif + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { + if (!pDev) + return Error(); + log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); +#if _MSC_VER && _WIN64 + lowlatency_ctx.init_al2(pDev); + switch (pSetLatencyMarkerParams->markerType) { + case SIMULATION_START: + if (lowlatency_ctx.call_spot != SimulationStart) break; + log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); + break; + case INPUT_SAMPLE: + if (lowlatency_ctx.call_spot == SleepCall) break; + lowlatency_ctx.call_spot = InputSample; + log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); + break; + case PRESENT_START: + if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); + } +#endif + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { + if (!pDevice) + return Error(); +#if _MSC_VER && _WIN64 + lowlatency_ctx.init_al2(pDevice); + lowlatency_ctx.call_spot = SleepCall; + log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); +#endif + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { + log("SetReflexSync"); + log(std::format("\tdisable: {}", (unsigned long)pSetReflexSyncParams->bDisable)); + log(std::format("\tenable: {}", (unsigned long)pSetReflexSyncParams->bEnable)); + log(std::format("\ttimeInQueueUs: {}", (signed long)pSetReflexSyncParams->timeInQueueUs)); + log(std::format("\ttimeInQueueUsTarget: {}", (unsigned long)pSetReflexSyncParams->timeInQueueUsTarget)); + log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->vblankIntervalUs)); + log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->version)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { + *pSupported = true; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize) { + if (pData == nullptr) + return Error(NVAPI_INVALID_POINTER); + + switch (type) { + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS)) + return Error(NVAPI_INVALID_ARGUMENT); + + // let's hope that NvAPI_D3D12_IsNvShaderExtnOpCodeSupported returning false is enough to discourage games from attempting to use Shader Execution Reordering + *(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS*)pData = NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAP_NONE; + break; + + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS)) + return Error(NVAPI_INVALID_POINTER); + + *(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_NONE; + break; + + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS)) + return Error(NVAPI_INVALID_POINTER); + + *(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE; + break; + + default: + return Error(NVAPI_INVALID_POINTER); + } + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { + // VKD3D-Proton does not know any NVIDIA intrinsics + *pSupported = false; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread() { + return Ok(); + } + + static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { + d3dDesc->Type = nvDesc->type; + // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed + d3dDesc->Flags = static_cast(nvDesc->flags & 0x3f); + d3dDesc->NumDescs = nvDesc->numDescs; + d3dDesc->DescsLayout = nvDesc->descsLayout; + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + d3dDesc->InstanceDescs = nvDesc->instanceDescs; + return true; + } + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) { + d3dDesc->ppGeometryDescs = reinterpret_cast(nvDesc->ppGeometryDescs); + return true; + } + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY) { + geometryDescs.resize(d3dDesc->NumDescs); + + for (unsigned i = 0; i < d3dDesc->NumDescs; ++i) { + auto& d3dGeoDesc = geometryDescs[i]; + auto& nvGeoDesc = *reinterpret_cast(reinterpret_cast(nvDesc->pGeometryDescs) + (i * nvDesc->geometryDescStrideInBytes)); + + d3dGeoDesc.Flags = nvGeoDesc.flags; + + switch (nvGeoDesc.type) { + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES_EX: + d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + d3dGeoDesc.Triangles = nvGeoDesc.triangles; + break; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS_EX: + d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + d3dGeoDesc.AABBs = nvGeoDesc.aabbs; + break; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this + log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); + return false; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this + log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); + return false; + default: + log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); + return false; + } + } + + d3dDesc->pGeometryDescs = geometryDescs.data(); + return true; + } + + return false; + } + + NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams) { + std::vector geometryDescs{}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS desc{}; + + if (!ConvertBuildRaytracingAccelerationStructureInputs(pParams->pDesc, geometryDescs, &desc)) + return Error(NVAPI_INVALID_ARGUMENT); + + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&desc, pParams->pInfo); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams) { + std::vector geometryDescs{}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = { + .DestAccelerationStructureData = pParams->pDesc->destAccelerationStructureData, + .Inputs = {}, + .SourceAccelerationStructureData = pParams->pDesc->sourceAccelerationStructureData, + .ScratchAccelerationStructureData = pParams->pDesc->scratchAccelerationStructureData, + }; + + if (!ConvertBuildRaytracingAccelerationStructureInputs(&pParams->pDesc->inputs, geometryDescs, &desc.Inputs)) + return Error(NVAPI_INVALID_ARGUMENT); + + pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { +#if _MSC_VER && _WIN64 + if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { + constexpr unsigned int history_size = 10; + static NvU64 counter = 0; + static NvU64 previous_frame_ids[history_size] = {}; + static NvU64 previous_frame_id = 0; + NvU64 current_frame_id = pSetAsyncFrameMarkerParams->frameID; + + previous_frame_ids[counter%history_size] = current_frame_id; + counter++; + + std::unordered_set seen; + int repeat_count = 0; + for (const int& frame_id : previous_frame_ids) { + if (seen.contains(frame_id)) repeat_count++; + else seen.insert(frame_id); + } + + if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; + else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; + + if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id != current_frame_id); + previous_frame_id = current_frame_id; + } +#endif + log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session) { + *session = drsSession; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { + *profile = drsProfile; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { + log(std::format("Missing setting: {}", settingId)); + return Error(NVAPI_SETTING_NOT_FOUND); + } + + NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Unload() { +#if _MSC_VER && _WIN64 + lowlatency_ctx.unload(); +#endif + return Ok(); + } + + NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk) { + std::fill(pMiscUnk, pMiscUnk + 4, 0x1); + return Ok(); + } + + NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown) { + return Ok(); + } + + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime) { +#if _MSC_VER && _WIN64 + if (!call_spot || !waitTarget || !latency || !frameTime) return Error(NVAPI_INVALID_POINTER); + + if (lowlatency_ctx.mode != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); + *call_spot = (uint64_t)lowlatency_ctx.call_spot; + + *waitTarget = lowlatency_ctx.lfx_stats.target; + *latency = lowlatency_ctx.lfx_stats.latency; + *frameTime = lowlatency_ctx.lfx_stats.frameTime; + + return Ok(); +#else + return Error(NVAPI_DATA_NOT_FOUND); +#endif + } } \ No newline at end of file From 7359d121efdefae5e069a58585f7edd7f7f91a77 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:52:30 +0200 Subject: [PATCH 10/18] Fix compilation on mingw LatencyFlex is having issues when compiled on mingw --- OptiScaler/nvapi/fakenvapi/log.cpp | 2 +- OptiScaler/nvapi/fakenvapi/lowlatency.h | 53 ++++++++++++++++++------- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 14 +------ OptiScaler/nvapi/fakenvapi/nvapi.h | 4 -- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 933da4a1..38d12e75 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -29,7 +29,7 @@ inline std::string extractFunctionName(const std::string& signature) { return signature.substr(start, end - start); } -inline void log(const std::string& log) { +void log(const std::string& log) { std::ostringstream oss; oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; *logStream << oss.str(); diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index 3673bb7b..1e68f238 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #if defined __MINGW64__ || defined __MINGW32__ #include "../include/d3d12.h" @@ -7,8 +9,10 @@ #include #endif +#if _MSC_VER && _WIN64 #include "../include/ffx_antilag2_dx12.h" #include "../include/ffx_antilag2_dx11.h" +#endif #include "../include/latencyflex.h" @@ -26,20 +30,21 @@ enum CallSpot { }; struct LFXStats { - uint64_t latency = {}; - uint64_t frameTime = {}; - uint64_t target = {}; - uint64_t lfx_frame_id = {}; - bool needs_reset = false; - + uint64_t latency = 0; + uint64_t frameTime = 1; + uint64_t target = 0; + uint64_t lfx_frame_id = 0; + bool needs_reset = false; }; class LowLatency { +#if _MSC_VER && _WIN64 AMD::AntiLag2DX12::Context context_dx12 = {}; AMD::AntiLag2DX11::Context context_dx11 = {}; +#endif + lfx::LatencyFleX *lf; unsigned long min_interval_us = 0; bool al_available = false; - lfx::LatencyFleX *lf; static inline uint64_t GetTimestamp() { LARGE_INTEGER frequency; @@ -52,12 +57,17 @@ class LowLatency { public: CallSpot call_spot = SimulationStart; +#if _MSC_VER && _WIN64 Mode mode = AntiLag2; +#else + Mode mode = LatencyFlex; +#endif LFXStats lfx_stats = {}; bool fg = false; bool active = true; inline HRESULT init_al2(IUnknown *pDevice) { +#if _MSC_VER && _WIN64 if (mode == AntiLag2 && !context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { ID3D12Device* device = nullptr; HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); @@ -69,9 +79,16 @@ public: } al_available = init_return == S_OK; } +#else + al_available = false; +#endif return 0x2137; } + void init_lfx() { + lf = new lfx::LatencyFleX(); + } + inline HRESULT update() { if (!active) return S_OK; @@ -82,12 +99,14 @@ public: log(std::format("FG status: {}", fg ? "enabled" : "disabled")); if (mode == AntiLag2) { +#if _MSC_VER && _WIN64 if (lfx_stats.lfx_frame_id != 1) lfx_stats.needs_reset = true; int max_fps = min_interval_us > 0 ? 1000000 / min_interval_us : 0; if (context_dx12.m_pAntiLagAPI) return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); else return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); +#endif } else if (mode == LatencyFlex) { if (lfx_stats.needs_reset) { log("LFX Reset"); @@ -102,8 +121,7 @@ public: lf->target_frame_time = 1000 * min_interval_us; lf->EndFrame(lfx_stats.lfx_frame_id, currentTimestamp, &lfx_stats.latency, &lfx_stats.frameTime); - // log(std::format("LFX latency: {}", lfx_stats.latency)); - // log(std::format("LFX frameTime: {}", lfx_stats.frameTime)); + log(std::format("LFX latency: {}, frameTime: {}, currentTimestamp: {}", lfx_stats.latency, lfx_stats.frameTime, currentTimestamp)); lfx_stats.lfx_frame_id++; lfx_stats.target = lf->GetWaitTarget(lfx_stats.lfx_frame_id); @@ -119,7 +137,8 @@ public: timestamp = lfx_stats.target; timeout_events = 0; } - std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); + // if (lfx_stats.lfx_frame_id > 30) + std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); } else { timestamp = currentTimestamp; } @@ -131,24 +150,30 @@ public: } inline HRESULT set_fg_type(bool interpolated) { +#if _MSC_VER && _WIN64 return AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated); +#else + return S_OK; +#endif } inline HRESULT mark_end_of_rendering() { +#if _MSC_VER && _WIN64 return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); +#else + return S_OK; +#endif } inline void unload() { +#if _MSC_VER && _WIN64 if (context_dx12.m_pAntiLagAPI) AMD::AntiLag2DX12::DeInitialize(&context_dx12); if (context_dx11.m_pAntiLagAPI) AMD::AntiLag2DX11::DeInitialize(&context_dx11); +#endif } void set_min_interval_us(unsigned long interval_us) { log(std::format("Max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0)); min_interval_us = interval_us; } - - void init_lfx() { - lf = new lfx::LatencyFleX(); - } }; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 6e5fe71b..3c57a893 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -305,10 +305,8 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { -#if _MSC_VER && _WIN64 lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; // untested lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); -#endif return Ok(); } @@ -316,7 +314,6 @@ namespace nvd { if (!pDev) return Error(); log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); -#if _MSC_VER && _WIN64 lowlatency_ctx.init_al2(pDev); switch (pSetLatencyMarkerParams->markerType) { case SIMULATION_START: @@ -331,18 +328,15 @@ namespace nvd { case PRESENT_START: if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); } -#endif return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { if (!pDevice) return Error(); -#if _MSC_VER && _WIN64 lowlatency_ctx.init_al2(pDevice); lowlatency_ctx.call_spot = SleepCall; log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); -#endif return Ok(); } @@ -519,7 +513,6 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { -#if _MSC_VER && _WIN64 if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { constexpr unsigned int history_size = 10; static NvU64 counter = 0; @@ -531,8 +524,8 @@ namespace nvd { counter++; std::unordered_set seen; - int repeat_count = 0; - for (const int& frame_id : previous_frame_ids) { + unsigned int repeat_count = 0; + for (const NvU64& frame_id : previous_frame_ids) { if (seen.contains(frame_id)) repeat_count++; else seen.insert(frame_id); } @@ -543,7 +536,6 @@ namespace nvd { if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id != current_frame_id); previous_frame_id = current_frame_id; } -#endif log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); return Ok(); } @@ -572,9 +564,7 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_Unload() { -#if _MSC_VER && _WIN64 lowlatency_ctx.unload(); -#endif return Ok(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index 652d5159..a2aa20b2 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -13,9 +13,7 @@ #endif #include -#if _MSC_VER && _WIN64 #include "lowlatency.h" -#endif #include "util.h" #include "spoofInfo.h" @@ -32,9 +30,7 @@ namespace nvd { static UINT subSysId; static UINT revisionId; -#if _MSC_VER && _WIN64 static LowLatency lowlatency_ctx; -#endif NvAPI_Status __cdecl NvAPI_Initialize(); NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc); From c7443b218cb9a9aff93b76dda30176ac1d53c89a Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Tue, 10 Sep 2024 02:10:26 +0200 Subject: [PATCH 11/18] Clean up Signed-off-by: FakeMichau <49685661+FakeMichau@users.noreply.github.com> --- OptiScaler/nvapi/fakenvapi/lowlatency.h | 49 +++++++++++++------------ OptiScaler/nvapi/fakenvapi/nvapi.cpp | 13 ++++--- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index 1e68f238..1e6fc2c5 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -31,7 +31,7 @@ enum CallSpot { struct LFXStats { uint64_t latency = 0; - uint64_t frameTime = 1; + uint64_t frame_time = 1; uint64_t target = 0; uint64_t lfx_frame_id = 0; bool needs_reset = false; @@ -41,6 +41,9 @@ class LowLatency { #if _MSC_VER && _WIN64 AMD::AntiLag2DX12::Context context_dx12 = {}; AMD::AntiLag2DX11::Context context_dx11 = {}; + Mode mode = AntiLag2; +#else + Mode mode = LatencyFlex; #endif lfx::LatencyFleX *lf; unsigned long min_interval_us = 0; @@ -57,14 +60,10 @@ class LowLatency { public: CallSpot call_spot = SimulationStart; -#if _MSC_VER && _WIN64 - Mode mode = AntiLag2; -#else - Mode mode = LatencyFlex; -#endif LFXStats lfx_stats = {}; bool fg = false; bool active = true; + bool force_lfx = false; inline HRESULT init_al2(IUnknown *pDevice) { #if _MSC_VER && _WIN64 @@ -90,9 +89,9 @@ public: } inline HRESULT update() { - if (!active) return S_OK; + if (!active) return S_FALSE; - if (al_available) mode = AntiLag2; + if (al_available && !force_lfx) mode = AntiLag2; else mode = LatencyFlex; log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); @@ -114,33 +113,31 @@ public: lfx_stats.needs_reset = false; lf->Reset(); } - uint64_t currentTimestamp = GetTimestamp(); + uint64_t current_timestamp = GetTimestamp(); uint64_t timestamp; // Set FPS Limiter lf->target_frame_time = 1000 * min_interval_us; - lf->EndFrame(lfx_stats.lfx_frame_id, currentTimestamp, &lfx_stats.latency, &lfx_stats.frameTime); - log(std::format("LFX latency: {}, frameTime: {}, currentTimestamp: {}", lfx_stats.latency, lfx_stats.frameTime, currentTimestamp)); + lf->EndFrame(lfx_stats.lfx_frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); + log(std::format("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp)); lfx_stats.lfx_frame_id++; lfx_stats.target = lf->GetWaitTarget(lfx_stats.lfx_frame_id); - auto diff = lfx_stats.target - currentTimestamp; - if (lfx_stats.target > currentTimestamp) { + if (lfx_stats.target > current_timestamp) { static uint64_t timeout_events = 0; - uint64_t timeout_timestamp = currentTimestamp + 50000000ULL; + uint64_t timeout_timestamp = current_timestamp + 50000000ULL; if (lfx_stats.target > timeout_timestamp) { timestamp = timeout_timestamp; timeout_events++; - if (timeout_events > 5) lfx_stats.needs_reset = true; + lfx_stats.needs_reset = timeout_events > 5; } else { timestamp = lfx_stats.target; timeout_events = 0; } - // if (lfx_stats.lfx_frame_id > 30) - std::this_thread::sleep_for(std::chrono::nanoseconds(diff)); + std::this_thread::sleep_for(std::chrono::nanoseconds(lfx_stats.target - current_timestamp)); } else { - timestamp = currentTimestamp; + timestamp = current_timestamp; } lf->BeginFrame(lfx_stats.lfx_frame_id, lfx_stats.target, timestamp); @@ -151,18 +148,18 @@ public: inline HRESULT set_fg_type(bool interpolated) { #if _MSC_VER && _WIN64 - return AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated); -#else - return S_OK; + if (mode == AntiLag2) + return AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated); #endif + return S_FALSE; } inline HRESULT mark_end_of_rendering() { #if _MSC_VER && _WIN64 - return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); -#else - return S_OK; + if (mode == AntiLag2) + return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); #endif + return S_FALSE; } inline void unload() { @@ -176,4 +173,8 @@ public: log(std::format("Max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0)); min_interval_us = interval_us; } + + Mode get_mode() { + return mode; + } }; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 3c57a893..0591a82c 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -305,7 +305,8 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { - lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; // untested + lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; + // lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; // FOR TESTING lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); return Ok(); } @@ -577,16 +578,16 @@ namespace nvd { return Ok(); } - NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime) { + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* target, uint64_t* latency, uint64_t* frame_time) { #if _MSC_VER && _WIN64 - if (!call_spot || !waitTarget || !latency || !frameTime) return Error(NVAPI_INVALID_POINTER); + if (!call_spot || !target || !latency || !frame_time) return Error(NVAPI_INVALID_POINTER); - if (lowlatency_ctx.mode != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); + if (lowlatency_ctx.get_mode() != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); *call_spot = (uint64_t)lowlatency_ctx.call_spot; - *waitTarget = lowlatency_ctx.lfx_stats.target; + *target = lowlatency_ctx.lfx_stats.target; *latency = lowlatency_ctx.lfx_stats.latency; - *frameTime = lowlatency_ctx.lfx_stats.frameTime; + *frame_time = lowlatency_ctx.lfx_stats.frame_time; return Ok(); #else From 29fb42b103e75d0f7147d53c0b8be0cf63cb5fe5 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Tue, 10 Sep 2024 02:17:08 +0200 Subject: [PATCH 12/18] Misc --- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 0591a82c..958a1814 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -328,6 +328,7 @@ namespace nvd { break; case PRESENT_START: if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); + break; } return Ok(); } @@ -342,13 +343,6 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { - log("SetReflexSync"); - log(std::format("\tdisable: {}", (unsigned long)pSetReflexSyncParams->bDisable)); - log(std::format("\tenable: {}", (unsigned long)pSetReflexSyncParams->bEnable)); - log(std::format("\ttimeInQueueUs: {}", (signed long)pSetReflexSyncParams->timeInQueueUs)); - log(std::format("\ttimeInQueueUsTarget: {}", (unsigned long)pSetReflexSyncParams->timeInQueueUsTarget)); - log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->vblankIntervalUs)); - log(std::format("\tvblankIntervalUs: {}", (unsigned long)pSetReflexSyncParams->version)); return Ok(); } @@ -428,6 +422,7 @@ namespace nvd { return Ok(); } + // Taken directly from dxvk-nvapi static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { d3dDesc->Type = nvDesc->type; // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed From ba9bf7f15896c73fabfceeeed6cc4f64d73ab0f7 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Tue, 10 Sep 2024 04:41:54 +0200 Subject: [PATCH 13/18] Skip code when not logging --- OptiScaler/nvapi/fakenvapi/log.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 38d12e75..d2cb696e 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -30,18 +30,21 @@ inline std::string extractFunctionName(const std::string& signature) { } void log(const std::string& log) { + if (logStream == &null) return; std::ostringstream oss; oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; *logStream << oss.str(); } NvAPI_Status Ok(const std::source_location& location) { - // log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); + if (logStream != &null) + log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); return NVAPI_OK; } NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { - log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); + if (logStream != &null) + log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); return status; } From 990ffba23d0b376ebc8c11730a479e668e2ddd2b Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:26:59 +0200 Subject: [PATCH 14/18] Clean up LFX + switch to LFX when FG and an FPS cap are used AL2 doesn't seem to support limiting the framerate when used with FG --- OptiScaler/nvapi/fakenvapi/lowlatency.h | 28 ++++++++++++++----------- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 2 +- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index 1e6fc2c5..82b32ef1 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -33,7 +33,7 @@ struct LFXStats { uint64_t latency = 0; uint64_t frame_time = 1; uint64_t target = 0; - uint64_t lfx_frame_id = 0; + uint64_t frame_id = 0; bool needs_reset = false; }; @@ -91,25 +91,27 @@ public: inline HRESULT update() { if (!active) return S_FALSE; - if (al_available && !force_lfx) mode = AntiLag2; - else mode = LatencyFlex; + if (al_available && !force_lfx && (min_interval_us == 0 || !fg)) + mode = AntiLag2; + else + mode = LatencyFlex; log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); log(std::format("FG status: {}", fg ? "enabled" : "disabled")); if (mode == AntiLag2) { #if _MSC_VER && _WIN64 - if (lfx_stats.lfx_frame_id != 1) lfx_stats.needs_reset = true; + if (lfx_stats.frame_id != 1) lfx_stats.needs_reset = true; int max_fps = min_interval_us > 0 ? 1000000 / min_interval_us : 0; if (context_dx12.m_pAntiLagAPI) return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); - else + else if (context_dx11.m_pAntiLagAPI) return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); #endif } else if (mode == LatencyFlex) { if (lfx_stats.needs_reset) { log("LFX Reset"); - lfx_stats.lfx_frame_id = 1; + lfx_stats.frame_id = 1; lfx_stats.needs_reset = false; lf->Reset(); } @@ -119,12 +121,14 @@ public: // Set FPS Limiter lf->target_frame_time = 1000 * min_interval_us; - lf->EndFrame(lfx_stats.lfx_frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); + lf->EndFrame(lfx_stats.frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); log(std::format("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp)); - lfx_stats.lfx_frame_id++; - lfx_stats.target = lf->GetWaitTarget(lfx_stats.lfx_frame_id); + lfx_stats.frame_id++; + lfx_stats.target = lf->GetWaitTarget(lfx_stats.frame_id); if (lfx_stats.target > current_timestamp) { + uint64_t extra_delay = 0; + // uint64_t extra_delay = (lfx_stats.target - current_timestamp) * 0.15; static uint64_t timeout_events = 0; uint64_t timeout_timestamp = current_timestamp + 50000000ULL; if (lfx_stats.target > timeout_timestamp) { @@ -132,15 +136,15 @@ public: timeout_events++; lfx_stats.needs_reset = timeout_events > 5; } else { - timestamp = lfx_stats.target; + timestamp = lfx_stats.target + extra_delay; timeout_events = 0; } - std::this_thread::sleep_for(std::chrono::nanoseconds(lfx_stats.target - current_timestamp)); + std::this_thread::sleep_for(std::chrono::nanoseconds(lfx_stats.target + extra_delay - current_timestamp)); } else { timestamp = current_timestamp; } - lf->BeginFrame(lfx_stats.lfx_frame_id, lfx_stats.target, timestamp); + lf->BeginFrame(lfx_stats.frame_id, lfx_stats.target, timestamp); return S_OK; } return S_FALSE; diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 958a1814..18cc3821 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -529,7 +529,7 @@ namespace nvd { if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; - if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id != current_frame_id); + if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id == current_frame_id); previous_frame_id = current_frame_id; } log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); From 7c0df54113a13d66d338e545aa0040eac835e884 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:17:31 +0200 Subject: [PATCH 15/18] Clean up function names --- OptiScaler/nvapi/fakenvapi/main.cpp | 14 +++++++--- OptiScaler/nvapi/fakenvapi/nvapi.cpp | 40 +++++++++++++++++++++------- OptiScaler/nvapi/fakenvapi/nvapi.h | 6 +++-- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index b5255cde..adf01eda 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -18,7 +18,11 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { auto logEnv = std::getenv("NVAPI_LOG"); +#ifdef TESTING + bool force_log = true; +#else bool force_log = false; +#endif switch (fdwReason) { case DLL_PROCESS_ATTACH: if ((logEnv && *logEnv == '1') || force_log) @@ -38,8 +42,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { NVAPI_INTERFACE_TABLE additional_interface_table[] = { { "NvAPI_Diag_ReportCallStart", 0x33c7358c }, { "NvAPI_Diag_ReportCallReturn", 0x593e8644 }, - { "MISC_unknown", 0xe9b009b9 }, - { "MISC_vulkan", 0x17d13d6 }, + { "NvAPI_Unknown_1", 0xe9b009b9 }, + { "NvAPI_Vulkan_1", 0x17d13d6 }, { "Dummy_GetLatency", 0x21372137 } }; @@ -125,12 +129,14 @@ namespace nvd { INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_SetAsyncFrameMarker) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_CreateSession) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_LoadSettings) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SaveSettings) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetBaseProfile) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetSetting) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SetSetting) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_DestroySession) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unknown_1) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_1) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unload) - INSERT_AND_RETURN_WHEN_EQUALS(MISC_unknown) - INSERT_AND_RETURN_WHEN_EQUALS(MISC_vulkan) INSERT_AND_RETURN_WHEN_EQUALS(Dummy_GetLatency) log(std::format("{}: not implemented, placeholder given", it->func)); diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/nvapi.cpp index 18cc3821..5869bd3c 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/nvapi.cpp @@ -297,6 +297,9 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { + pGetSleepStatusParams->bLowLatencyMode = lowlatency_ctx.active; + pGetSleepStatusParams->bFsVrr = true; + pGetSleepStatusParams->bCplVsyncOn = true; return Ok(); } @@ -306,7 +309,9 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; - // lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; // FOR TESTING +#ifdef TESTING + lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; +#endif lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); return Ok(); } @@ -501,7 +506,12 @@ namespace nvd { return Error(NVAPI_INVALID_ARGUMENT); pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); - return Ok(); + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging } NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { @@ -545,6 +555,10 @@ namespace nvd { return Ok(); } + NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session) { + return Ok(); + } + NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { *profile = drsProfile; return Ok(); @@ -552,24 +566,30 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { log(std::format("Missing setting: {}", settingId)); - return Error(NVAPI_SETTING_NOT_FOUND); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { + log("NvAPI_DRS_SetSetting"); + log(std::format("\tsettingId: {}", pSetting->settingId)); + return NVAPI_OK; } NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { return Ok(); } - NvAPI_Status __cdecl NvAPI_Unload() { - lowlatency_ctx.unload(); - return Ok(); - } - - NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk) { + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { std::fill(pMiscUnk, pMiscUnk + 4, 0x1); return Ok(); } - NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown) { + NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Unload() { + lowlatency_ctx.unload(); return Ok(); } diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/nvapi.h index a2aa20b2..e6e6ebe2 100755 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/nvapi.h @@ -82,11 +82,13 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams); NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session); NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session); + NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session); NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile); NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting); + NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting); NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session); + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk); + NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown); NvAPI_Status __cdecl NvAPI_Unload(); - NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk); - NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown); NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime); } \ No newline at end of file From 74281f20c04c0801a8685b058be8740235ba5629 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Thu, 12 Sep 2024 19:52:40 +0200 Subject: [PATCH 16/18] Change include to external --- .../fakenvapi/{nvapi.cpp => fakenvapi.cpp} | 1226 +++++++++-------- .../nvapi/fakenvapi/{nvapi.h => fakenvapi.h} | 1 - OptiScaler/nvapi/fakenvapi/log.h | 3 +- OptiScaler/nvapi/fakenvapi/lowlatency.h | 8 +- OptiScaler/nvapi/fakenvapi/main.cpp | 7 +- OptiScaler/nvapi/fakenvapi/meson.build | 2 +- OptiScaler/nvapi/fakenvapi/spoofInfo.cpp | 14 - OptiScaler/nvapi/fakenvapi/spoofInfo.h | 19 - OptiScaler/nvapi/fakenvapi/util.h | 3 +- 9 files changed, 625 insertions(+), 658 deletions(-) rename OptiScaler/nvapi/fakenvapi/{nvapi.cpp => fakenvapi.cpp} (95%) mode change 100755 => 100644 rename OptiScaler/nvapi/fakenvapi/{nvapi.h => fakenvapi.h} (99%) mode change 100755 => 100644 delete mode 100644 OptiScaler/nvapi/fakenvapi/spoofInfo.cpp delete mode 100644 OptiScaler/nvapi/fakenvapi/spoofInfo.h diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp old mode 100755 new mode 100644 similarity index 95% rename from OptiScaler/nvapi/fakenvapi/nvapi.cpp rename to OptiScaler/nvapi/fakenvapi/fakenvapi.cpp index 5869bd3c..7f976356 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp @@ -1,612 +1,616 @@ -#include "nvapi.h" -#include - -namespace nvd { - NvAPI_Status __cdecl NvAPI_Initialize() { - IDXGIFactory1* pFactory = nullptr; - if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { - log("Failed to create DXGI Factory"); - return Error(); - } - - IDXGIAdapter1* pAdapter = nullptr; - if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { - log("Failed to enumerate adapters"); - pFactory->Release(); - return Error(); - } - - DXGI_ADAPTER_DESC1 adapterDesc; - if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { - log("Failed to get adapter description"); - pAdapter->Release(); - pFactory->Release(); - return Error(); - } - - luid = adapterDesc.AdapterLuid; - deviceId = adapterDesc.DeviceId; - vendorId = adapterDesc.VendorId; - subSysId = adapterDesc.SubSysId; - revisionId = adapterDesc.Revision; - - pAdapter->Release(); - pFactory->Release(); - - lowlatency_ctx.init_lfx(); - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc) { - tonvss(desc, "NvAPI dummy"); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count) { - handles[0] = nullptr; - *count = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count) { - handles[0] = nullptr; - *count = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle) { - if (displayId == 0) { - return Ok(); - } - return Error(NVAPI_END_ENUMERATION); - } - - NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { - *logicalHandle = nullptr; - return Ok(); - } - - - NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId) { - *pGpuId = 42; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU) { - *pPhysicalGPU = nullptr; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32* pGpuCount) { - nvGPUHandle[0] = nullptr; - *pGpuCount = 1; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { - std::string error = fromErrorNr(status); - log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); - tonvss(szMsg, error); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo) { - auto pComputeTopoV1 = reinterpret_cast(pComputeTopo); - pComputeTopoV1->gpuCount = 1; - pComputeTopoV1->computeGpus[0].hPhysicalGpu = nullptr; - pComputeTopoV1->computeGpus[0].flags = NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_CAPABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_ENABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_RECOMMENDED; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags) { - *displayCount = 0; // no displays connected, may cause issues - // NVAPI_NVIDIA_DISPLAY_NOT_FOUND could be considered - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { - archInfo->architecture = spoof::arch; - archInfo->architecture_id = spoof::arch; - archInfo->implementation = spoof::implementation; - archInfo->implementation_id = spoof::implementation; - archInfo->revision = spoof::revision; - archInfo->revision_id = spoof::revision; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData) { - memcpy(logicalGpuData->pOSAdapterId, &luid, sizeof(luid)); - logicalGpuData->physicalGpuHandles[0] = nullptr; - logicalGpuData->physicalGpuCount = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId) { - *pDeviceId = (deviceId << 16) | vendorId; - *pSubSystemId = subSysId; - *pRevisionId = revisionId; - *pExtDeviceId = deviceId; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { - tonvss(szName, spoof::fullGPUName); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount) { - *pCount = 1; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs) { - if (pClkFreqs == nullptr) - return Error(NVAPI_INVALID_ARGUMENT); - - if (pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_1 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_2 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_3) - return Error(NVAPI_INCOMPATIBLE_STRUCT_VERSION); - - if (pClkFreqs->ClockType != static_cast(NV_GPU_CLOCK_FREQUENCIES_CURRENT_FREQ)) { - return Error(NVAPI_NOT_SUPPORTED); - } - - // Reset all clock data for all domains - for (auto& domain : pClkFreqs->domain) { - domain.bIsPresent = 0; - domain.frequency = 0; - } - - unsigned int clock = 1600; - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].frequency = (clock * 1000); - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].frequency = (clock * 1000); - - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].bIsPresent = 1; - pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].frequency = (clock * 1000); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) { - memcpy(pOSAdapterId, &luid, sizeof(luid)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo) { - if (!pPstatesInfo) - return Error(); - - // Initialize the structure with mock data - pPstatesInfo->version = NV_GPU_PERF_PSTATES20_INFO_VER; - pPstatesInfo->numPstates = 2; // Example: 2 P-states - pPstatesInfo->numClocks = 3; - pPstatesInfo->numBaseVoltages = 1; - pPstatesInfo->ov.numVoltages = 0; - - // Fill mock data for P-state 0 - pPstatesInfo->pstates[0].pstateId = NVAPI_GPU_PERF_PSTATE_P0; - pPstatesInfo->pstates[0].bIsEditable = false; - pPstatesInfo->pstates[0].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[0].baseVoltages[0].volt_uV = 1000000; // 1V - pPstatesInfo->pstates[0].baseVoltages[0].bIsEditable = false; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.value = 1000; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.min = 0; - pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.max = 0; - - // Fill mock data for P-state 1 - pPstatesInfo->pstates[1].pstateId = NVAPI_GPU_PERF_PSTATE_P1; - pPstatesInfo->pstates[1].bIsEditable = false; - pPstatesInfo->pstates[1].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.min = 800; - pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.max = 1200; - pPstatesInfo->pstates[1].baseVoltages[0].volt_uV = 1000000; // 1V - pPstatesInfo->pstates[1].baseVoltages[0].bIsEditable = false; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.value = 1000; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.min = 0; - pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.max = 0; - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { - *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { - *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected) { - for (int i = 0; i < NV_MOSAIC_MAX_DISPLAYS; i++) { - viewports[i].top = 0; - viewports[i].left = 0; - viewports[i].right = 0; - viewports[i].bottom = 0; - } - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { - spoof::driverInfo(driverInfo); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { - memset(pDriverVersion, 0, sizeof(NvU32)); - memcpy(pDriverVersion, &spoof::driverVersion, sizeof(NvU32)); - // *pDriverVersion = spoof::driverVersion; - tonvss(szBuildBranchString, spoof::buildBranch); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId) { - *displayId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId) { - *hPhysicalGpu = nullptr; - *outputId = 0; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle) { - *pHandle = (NVDX_ObjectHandle)pResource; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { - return Error(NVAPI_NO_IMPLEMENTATION); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { - pGetSleepStatusParams->bLowLatencyMode = lowlatency_ctx.active; - pGetSleepStatusParams->bFsVrr = true; - pGetSleepStatusParams->bCplVsyncOn = true; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { - lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; -#ifdef TESTING - lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; -#endif - lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { - if (!pDev) - return Error(); - log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); - lowlatency_ctx.init_al2(pDev); - switch (pSetLatencyMarkerParams->markerType) { - case SIMULATION_START: - if (lowlatency_ctx.call_spot != SimulationStart) break; - log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); - break; - case INPUT_SAMPLE: - if (lowlatency_ctx.call_spot == SleepCall) break; - lowlatency_ctx.call_spot = InputSample; - log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); - break; - case PRESENT_START: - if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); - break; - } - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { - if (!pDevice) - return Error(); - lowlatency_ctx.init_al2(pDevice); - lowlatency_ctx.call_spot = SleepCall; - log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { - *pSupported = true; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext) { - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize) { - if (pData == nullptr) - return Error(NVAPI_INVALID_POINTER); - - switch (type) { - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS)) - return Error(NVAPI_INVALID_ARGUMENT); - - // let's hope that NvAPI_D3D12_IsNvShaderExtnOpCodeSupported returning false is enough to discourage games from attempting to use Shader Execution Reordering - *(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS*)pData = NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAP_NONE; - break; - - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS)) - return Error(NVAPI_INVALID_POINTER); - - *(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_NONE; - break; - - case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP: - if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS)) - return Error(NVAPI_INVALID_POINTER); - - *(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE; - break; - - default: - return Error(NVAPI_INVALID_POINTER); - } - - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { - // VKD3D-Proton does not know any NVIDIA intrinsics - *pSupported = false; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread() { - return Ok(); - } - - // Taken directly from dxvk-nvapi - static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { - d3dDesc->Type = nvDesc->type; - // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed - d3dDesc->Flags = static_cast(nvDesc->flags & 0x3f); - d3dDesc->NumDescs = nvDesc->numDescs; - d3dDesc->DescsLayout = nvDesc->descsLayout; - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - d3dDesc->InstanceDescs = nvDesc->instanceDescs; - return true; - } - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) { - d3dDesc->ppGeometryDescs = reinterpret_cast(nvDesc->ppGeometryDescs); - return true; - } - - if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY) { - geometryDescs.resize(d3dDesc->NumDescs); - - for (unsigned i = 0; i < d3dDesc->NumDescs; ++i) { - auto& d3dGeoDesc = geometryDescs[i]; - auto& nvGeoDesc = *reinterpret_cast(reinterpret_cast(nvDesc->pGeometryDescs) + (i * nvDesc->geometryDescStrideInBytes)); - - d3dGeoDesc.Flags = nvGeoDesc.flags; - - switch (nvGeoDesc.type) { - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES_EX: - d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - d3dGeoDesc.Triangles = nvGeoDesc.triangles; - break; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS_EX: - d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; - d3dGeoDesc.AABBs = nvGeoDesc.aabbs; - break; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this - log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); - return false; - case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this - log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); - return false; - default: - log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); - return false; - } - } - - d3dDesc->pGeometryDescs = geometryDescs.data(); - return true; - } - - return false; - } - - NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams) { - std::vector geometryDescs{}; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS desc{}; - - if (!ConvertBuildRaytracingAccelerationStructureInputs(pParams->pDesc, geometryDescs, &desc)) - return Error(NVAPI_INVALID_ARGUMENT); - - pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&desc, pParams->pInfo); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams) { - std::vector geometryDescs{}; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = { - .DestAccelerationStructureData = pParams->pDesc->destAccelerationStructureData, - .Inputs = {}, - .SourceAccelerationStructureData = pParams->pDesc->sourceAccelerationStructureData, - .ScratchAccelerationStructureData = pParams->pDesc->scratchAccelerationStructureData, - }; - - if (!ConvertBuildRaytracingAccelerationStructureInputs(&pParams->pDesc->inputs, geometryDescs, &desc.Inputs)) - return Error(NVAPI_INVALID_ARGUMENT); - - pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); - static bool logged = false; - if (!logged) { - logged = true; - return Ok(); - } - else return NVAPI_OK; //return without logging - } - - NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { - if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { - constexpr unsigned int history_size = 10; - static NvU64 counter = 0; - static NvU64 previous_frame_ids[history_size] = {}; - static NvU64 previous_frame_id = 0; - NvU64 current_frame_id = pSetAsyncFrameMarkerParams->frameID; - - previous_frame_ids[counter%history_size] = current_frame_id; - counter++; - - std::unordered_set seen; - unsigned int repeat_count = 0; - for (const NvU64& frame_id : previous_frame_ids) { - if (seen.contains(frame_id)) repeat_count++; - else seen.insert(frame_id); - } - - if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; - else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; - - if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id == current_frame_id); - previous_frame_id = current_frame_id; - } - log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session) { - *session = drsSession; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { - *profile = drsProfile; - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { - log(std::format("Missing setting: {}", settingId)); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { - log("NvAPI_DRS_SetSetting"); - log(std::format("\tsettingId: {}", pSetting->settingId)); - return NVAPI_OK; - } - - NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { - std::fill(pMiscUnk, pMiscUnk + 4, 0x1); - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown) { - return Ok(); - } - - NvAPI_Status __cdecl NvAPI_Unload() { - lowlatency_ctx.unload(); - return Ok(); - } - - NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* target, uint64_t* latency, uint64_t* frame_time) { -#if _MSC_VER && _WIN64 - if (!call_spot || !target || !latency || !frame_time) return Error(NVAPI_INVALID_POINTER); - - if (lowlatency_ctx.get_mode() != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); - *call_spot = (uint64_t)lowlatency_ctx.call_spot; - - *target = lowlatency_ctx.lfx_stats.target; - *latency = lowlatency_ctx.lfx_stats.latency; - *frame_time = lowlatency_ctx.lfx_stats.frame_time; - - return Ok(); -#else - return Error(NVAPI_DATA_NOT_FOUND); -#endif - } +#include "fakenvapi.h" +#include + +namespace nvd { + NvAPI_Status __cdecl NvAPI_Initialize() { + IDXGIFactory1* pFactory = nullptr; + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { + log("Failed to create DXGI Factory"); + return Error(); + } + + IDXGIAdapter1* pAdapter = nullptr; + if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { + log("Failed to enumerate adapters"); + pFactory->Release(); + return Error(); + } + + DXGI_ADAPTER_DESC1 adapterDesc; + if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { + log("Failed to get adapter description"); + pAdapter->Release(); + pFactory->Release(); + return Error(); + } + + luid = adapterDesc.AdapterLuid; + deviceId = adapterDesc.DeviceId; + vendorId = adapterDesc.VendorId; + subSysId = adapterDesc.SubSysId; + revisionId = adapterDesc.Revision; + + pAdapter->Release(); + pFactory->Release(); + + lowlatency_ctx.init_lfx(); + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc) { + tonvss(desc, "NvAPI dummy"); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count) { + handles[0] = nullptr; + *count = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count) { + handles[0] = nullptr; + *count = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle) { + if (displayId == 0) { + return Ok(); + } + return Error(NVAPI_END_ENUMERATION); + } + + NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { + *logicalHandle = nullptr; + return Ok(); + } + + + NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId) { + *pGpuId = 42; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU) { + *pPhysicalGPU = nullptr; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32* pGpuCount) { + nvGPUHandle[0] = nullptr; + *pGpuCount = 1; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { + std::string error = fromErrorNr(status); + log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); + tonvss(szMsg, error); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo) { + auto pComputeTopoV1 = reinterpret_cast(pComputeTopo); + pComputeTopoV1->gpuCount = 1; + pComputeTopoV1->computeGpus[0].hPhysicalGpu = nullptr; + pComputeTopoV1->computeGpus[0].flags = NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_CAPABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_ENABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_RECOMMENDED; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags) { + *displayCount = 0; // no displays connected, may cause issues + // NVAPI_NVIDIA_DISPLAY_NOT_FOUND could be considered + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { + archInfo->architecture = NV_GPU_ARCHITECTURE_AD100; + archInfo->architecture_id = NV_GPU_ARCHITECTURE_AD100; + archInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_AD102; + archInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_AD102; + archInfo->revision = NV_GPU_CHIP_REV_UNKNOWN; + archInfo->revision_id = NV_GPU_CHIP_REV_UNKNOWN; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData) { + memcpy(logicalGpuData->pOSAdapterId, &luid, sizeof(luid)); + logicalGpuData->physicalGpuHandles[0] = nullptr; + logicalGpuData->physicalGpuCount = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId) { + *pDeviceId = (deviceId << 16) | vendorId; + *pSubSystemId = subSysId; + *pRevisionId = revisionId; + *pExtDeviceId = deviceId; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { + tonvss(szName, "NVIDIA GeForce RTX 4090"); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount) { + *pCount = 1; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs) { + if (pClkFreqs == nullptr) + return Error(NVAPI_INVALID_ARGUMENT); + + if (pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_1 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_2 && pClkFreqs->version != NV_GPU_CLOCK_FREQUENCIES_VER_3) + return Error(NVAPI_INCOMPATIBLE_STRUCT_VERSION); + + if (pClkFreqs->ClockType != static_cast(NV_GPU_CLOCK_FREQUENCIES_CURRENT_FREQ)) { + return Error(NVAPI_NOT_SUPPORTED); + } + + // Reset all clock data for all domains + for (auto& domain : pClkFreqs->domain) { + domain.bIsPresent = 0; + domain.frequency = 0; + } + + unsigned int clock = 1600; + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].frequency = (clock * 1000); + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].frequency = (clock * 1000); + + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].bIsPresent = 1; + pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].frequency = (clock * 1000); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) { + memcpy(pOSAdapterId, &luid, sizeof(luid)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo) { + if (!pPstatesInfo) + return Error(); + + // Initialize the structure with mock data + pPstatesInfo->version = NV_GPU_PERF_PSTATES20_INFO_VER; + pPstatesInfo->numPstates = 2; // Example: 2 P-states + pPstatesInfo->numClocks = 3; + pPstatesInfo->numBaseVoltages = 1; + pPstatesInfo->ov.numVoltages = 0; + + // Fill mock data for P-state 0 + pPstatesInfo->pstates[0].pstateId = NVAPI_GPU_PERF_PSTATE_P0; + pPstatesInfo->pstates[0].bIsEditable = false; + pPstatesInfo->pstates[0].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[0].baseVoltages[0].volt_uV = 1000000; // 1V + pPstatesInfo->pstates[0].baseVoltages[0].bIsEditable = false; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.value = 1000; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.min = 0; + pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.max = 0; + + // Fill mock data for P-state 1 + pPstatesInfo->pstates[1].pstateId = NVAPI_GPU_PERF_PSTATE_P1; + pPstatesInfo->pstates[1].bIsEditable = false; + pPstatesInfo->pstates[1].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[0].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[1].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.min = 800; + pPstatesInfo->pstates[1].clocks[2].freqDelta_kHz.valueRange.max = 1200; + pPstatesInfo->pstates[1].baseVoltages[0].volt_uV = 1000000; // 1V + pPstatesInfo->pstates[1].baseVoltages[0].bIsEditable = false; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.value = 1000; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.min = 0; + pPstatesInfo->pstates[1].baseVoltages[0].voltDelta_uV.valueRange.max = 0; + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { + *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { + *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected) { + for (int i = 0; i < NV_MOSAIC_MAX_DISPLAYS; i++) { + viewports[i].top = 0; + viewports[i].left = 0; + viewports[i].right = 0; + viewports[i].bottom = 0; + } + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { + driverInfo->driverVersion = 99999; + tonvss(driverInfo->szBuildBranch, "buildBranch"); + driverInfo->bIsDCHDriver = 1; + driverInfo->bIsNVIDIAStudioPackage = 1; + driverInfo->bIsNVIDIARTXProductionBranchPackage = 1; + driverInfo->bIsNVIDIARTXNewFeatureBranchPackage = 1; + if (driverInfo->version == 2) + tonvss(driverInfo->szBuildBaseBranch, "buildBaseBranch"); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { + tonvss(szBuildBranchString, "buildBranch"); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId) { + *displayId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId) { + *hPhysicalGpu = nullptr; + *outputId = 0; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle) { + *pHandle = (NVDX_ObjectHandle)pResource; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { + return Error(NVAPI_NO_IMPLEMENTATION); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { + pGetSleepStatusParams->bLowLatencyMode = lowlatency_ctx.active; + pGetSleepStatusParams->bFsVrr = true; + pGetSleepStatusParams->bCplVsyncOn = true; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { + lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; +#ifdef TESTING + lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; +#endif + lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { + if (!pDev) + return Error(); + log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); + lowlatency_ctx.init_al2(pDev); + switch (pSetLatencyMarkerParams->markerType) { + case SIMULATION_START: + if (lowlatency_ctx.call_spot != SimulationStart) break; + log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); + break; + case INPUT_SAMPLE: + if (lowlatency_ctx.call_spot == SleepCall) break; + lowlatency_ctx.call_spot = InputSample; + log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); + break; + case PRESENT_START: + if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); + break; + } + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { + if (!pDevice) + return Error(); + lowlatency_ctx.init_al2(pDevice); + lowlatency_ctx.call_spot = SleepCall; + log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { + *pSupported = true; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext) { + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize) { + if (pData == nullptr) + return Error(NVAPI_INVALID_POINTER); + + switch (type) { + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS)) + return Error(NVAPI_INVALID_ARGUMENT); + + // let's hope that NvAPI_D3D12_IsNvShaderExtnOpCodeSupported returning false is enough to discourage games from attempting to use Shader Execution Reordering + *(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS*)pData = NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAP_NONE; + break; + + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS)) + return Error(NVAPI_INVALID_POINTER); + + *(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_NONE; + break; + + case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP: + if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS)) + return Error(NVAPI_INVALID_POINTER); + + *(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE; + break; + + default: + return Error(NVAPI_INVALID_POINTER); + } + + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { + // VKD3D-Proton does not know any NVIDIA intrinsics + *pSupported = false; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread() { + return Ok(); + } + + // Taken directly from dxvk-nvapi + static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { + d3dDesc->Type = nvDesc->type; + // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed + d3dDesc->Flags = static_cast(nvDesc->flags & 0x3f); + d3dDesc->NumDescs = nvDesc->numDescs; + d3dDesc->DescsLayout = nvDesc->descsLayout; + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + d3dDesc->InstanceDescs = nvDesc->instanceDescs; + return true; + } + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) { + d3dDesc->ppGeometryDescs = reinterpret_cast(nvDesc->ppGeometryDescs); + return true; + } + + if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY) { + geometryDescs.resize(d3dDesc->NumDescs); + + for (unsigned i = 0; i < d3dDesc->NumDescs; ++i) { + auto& d3dGeoDesc = geometryDescs[i]; + auto& nvGeoDesc = *reinterpret_cast(reinterpret_cast(nvDesc->pGeometryDescs) + (i * nvDesc->geometryDescStrideInBytes)); + + d3dGeoDesc.Flags = nvGeoDesc.flags; + + switch (nvGeoDesc.type) { + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES_EX: + d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + d3dGeoDesc.Triangles = nvGeoDesc.triangles; + break; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS_EX: + d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + d3dGeoDesc.AABBs = nvGeoDesc.aabbs; + break; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this + log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); + return false; + case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this + log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); + return false; + default: + log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); + return false; + } + } + + d3dDesc->pGeometryDescs = geometryDescs.data(); + return true; + } + + return false; + } + + NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams) { + std::vector geometryDescs{}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS desc{}; + + if (!ConvertBuildRaytracingAccelerationStructureInputs(pParams->pDesc, geometryDescs, &desc)) + return Error(NVAPI_INVALID_ARGUMENT); + + pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&desc, pParams->pInfo); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams) { + std::vector geometryDescs{}; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = { + .DestAccelerationStructureData = pParams->pDesc->destAccelerationStructureData, + .Inputs = {}, + .SourceAccelerationStructureData = pParams->pDesc->sourceAccelerationStructureData, + .ScratchAccelerationStructureData = pParams->pDesc->scratchAccelerationStructureData, + }; + + if (!ConvertBuildRaytracingAccelerationStructureInputs(&pParams->pDesc->inputs, geometryDescs, &desc.Inputs)) + return Error(NVAPI_INVALID_ARGUMENT); + + pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging + } + + NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { + if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { + constexpr unsigned int history_size = 10; + static NvU64 counter = 0; + static NvU64 previous_frame_ids[history_size] = {}; + static NvU64 previous_frame_id = 0; + NvU64 current_frame_id = pSetAsyncFrameMarkerParams->frameID; + + previous_frame_ids[counter%history_size] = current_frame_id; + counter++; + + std::unordered_set seen; + unsigned int repeat_count = 0; + for (const NvU64& frame_id : previous_frame_ids) { + if (seen.contains(frame_id)) repeat_count++; + else seen.insert(frame_id); + } + + if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; + else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; + + if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id == current_frame_id); + previous_frame_id = current_frame_id; + } + log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session) { + *session = drsSession; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { + *profile = drsProfile; + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { + log(std::format("Missing setting: {}", settingId)); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { + log("NvAPI_DRS_SetSetting"); + log(std::format("\tsettingId: {}", pSetting->settingId)); + return NVAPI_OK; + } + + NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { + std::fill(pMiscUnk, pMiscUnk + 4, 0x1); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown) { + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_Unload() { + lowlatency_ctx.unload(); + return Ok(); + } + + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* target, uint64_t* latency, uint64_t* frame_time) { +#if _MSC_VER && _WIN64 + if (!call_spot || !target || !latency || !frame_time) return Error(NVAPI_INVALID_POINTER); + + if (lowlatency_ctx.get_mode() != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); + *call_spot = (uint64_t)lowlatency_ctx.call_spot; + + *target = lowlatency_ctx.lfx_stats.target; + *latency = lowlatency_ctx.lfx_stats.latency; + *frame_time = lowlatency_ctx.lfx_stats.frame_time; + + return Ok(); +#else + return Error(NVAPI_DATA_NOT_FOUND); +#endif + } } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/fakenvapi.h old mode 100755 new mode 100644 similarity index 99% rename from OptiScaler/nvapi/fakenvapi/nvapi.h rename to OptiScaler/nvapi/fakenvapi/fakenvapi.h index e6e6ebe2..fea0b362 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/fakenvapi.h @@ -16,7 +16,6 @@ #include "lowlatency.h" #include "util.h" -#include "spoofInfo.h" #include "log.h" namespace nvd { diff --git a/OptiScaler/nvapi/fakenvapi/log.h b/OptiScaler/nvapi/fakenvapi/log.h index e447a4a8..98151f6c 100755 --- a/OptiScaler/nvapi/fakenvapi/log.h +++ b/OptiScaler/nvapi/fakenvapi/log.h @@ -1,5 +1,4 @@ #pragma once -#define _CRT_SECURE_NO_WARNINGS 1 #include #include #include @@ -8,7 +7,7 @@ #include #include #include "util.h" -#include "../include/nvapi.h" +#include "../external/nvapi.h" std::string getCurrentTimeFormatted(); void log(const std::string& log); diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index 82b32ef1..bc1fb4aa 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -4,17 +4,17 @@ #include #if defined __MINGW64__ || defined __MINGW32__ -#include "../include/d3d12.h" +#include "../external/d3d12.h" #else #include #endif #if _MSC_VER && _WIN64 -#include "../include/ffx_antilag2_dx12.h" -#include "../include/ffx_antilag2_dx11.h" +#include "../external/ffx_antilag2_dx12.h" +#include "../external/ffx_antilag2_dx11.h" #endif -#include "../include/latencyflex.h" +#include "../external/latencyflex.h" #include "log.h" diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index adf01eda..2b97023c 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -1,18 +1,17 @@ -#define _CRT_SECURE_NO_WARNINGS 1 #include #include #include #include #include -#include "../include/nvapi_interface.h" +#include "../external/nvapi_interface.h" #if defined __MINGW64__ || defined __MINGW32__ #include "../include/d3d12.h" #else #include #endif -#include "../include/nvapi.h" -#include "nvapi.h" +#include "../external/nvapi.h" +#include "fakenvapi.h" #include "log.h" diff --git a/OptiScaler/nvapi/fakenvapi/meson.build b/OptiScaler/nvapi/fakenvapi/meson.build index b7d2f9a7..83e0fc7a 100644 --- a/OptiScaler/nvapi/fakenvapi/meson.build +++ b/OptiScaler/nvapi/fakenvapi/meson.build @@ -1,6 +1,6 @@ dll = shared_library( 'nvapi'+target_suffix, - ['main.cpp', 'nvapi.cpp', 'spoofInfo.cpp', 'util.cpp', 'log.cpp'], + ['main.cpp', 'fakenvapi.cpp', 'util.cpp', 'log.cpp'], name_prefix : '', dependencies : [ lib_dxgi ], install: true diff --git a/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp b/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp deleted file mode 100644 index a0cc6f55..00000000 --- a/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "spoofInfo.h" - -namespace spoof { - void driverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { - driverInfo->driverVersion = driverVersion; - tonvss(driverInfo->szBuildBranch, buildBranch); - driverInfo->bIsDCHDriver = isDCHDriver; - driverInfo->bIsNVIDIAStudioPackage = isNVIDIAStudioPackage; - driverInfo->bIsNVIDIARTXProductionBranchPackage = isNVIDIARTXProductionBranchPackage; - driverInfo->bIsNVIDIARTXNewFeatureBranchPackage = isNVIDIARTXNewFeatureBranchPackage; - if (driverInfo->version == 2) - tonvss(driverInfo->szBuildBaseBranch, buildBaseBranch); - } -} \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/spoofInfo.h b/OptiScaler/nvapi/fakenvapi/spoofInfo.h deleted file mode 100644 index 23dace17..00000000 --- a/OptiScaler/nvapi/fakenvapi/spoofInfo.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "util.h" - -namespace spoof { - constexpr NvU32 driverVersion = 99999; - constexpr auto buildBranch = "buildBranch"; - constexpr NvU32 isDCHDriver = 1; - constexpr NvU32 isNVIDIAStudioPackage = 1; - constexpr NvU32 isNVIDIARTXProductionBranchPackage = 1; - constexpr NvU32 isNVIDIARTXNewFeatureBranchPackage = 1; - constexpr auto buildBaseBranch = "buildBaseBranch"; - - constexpr auto fullGPUName = "NVIDIA GeForce RTX 4090"; - constexpr NV_GPU_ARCHITECTURE_ID arch = NV_GPU_ARCHITECTURE_AD100; - constexpr NV_GPU_ARCH_IMPLEMENTATION_ID implementation = NV_GPU_ARCH_IMPLEMENTATION_AD102; - constexpr NV_GPU_CHIP_REVISION revision = NV_GPU_CHIP_REV_UNKNOWN; - - void driverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo); -} diff --git a/OptiScaler/nvapi/fakenvapi/util.h b/OptiScaler/nvapi/fakenvapi/util.h index b884f538..92751f70 100755 --- a/OptiScaler/nvapi/fakenvapi/util.h +++ b/OptiScaler/nvapi/fakenvapi/util.h @@ -1,6 +1,5 @@ #pragma once -#define _CRT_SECURE_NO_WARNINGS 1 -#include "../include/nvapi.h" +#include "../external/nvapi.h" #include #include #include From aab720b7b1ed1f7f0de552b6a5890ef6d6e29935 Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:27:34 +0200 Subject: [PATCH 17/18] Move logging to spdlog --- OptiScaler/nvapi/fakenvapi/fakenvapi.cpp | 31 ++++++------- OptiScaler/nvapi/fakenvapi/log.cpp | 58 +++++++----------------- OptiScaler/nvapi/fakenvapi/log.h | 6 +-- OptiScaler/nvapi/fakenvapi/lowlatency.h | 14 +++--- OptiScaler/nvapi/fakenvapi/main.cpp | 10 ++-- OptiScaler/nvapi/fakenvapi/meson.build | 1 + 6 files changed, 49 insertions(+), 71 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp index 7f976356..bbfb75e2 100644 --- a/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp @@ -5,20 +5,20 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_Initialize() { IDXGIFactory1* pFactory = nullptr; if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { - log("Failed to create DXGI Factory"); + spdlog::error("Failed to create DXGI Factory"); return Error(); } IDXGIAdapter1* pAdapter = nullptr; if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { - log("Failed to enumerate adapters"); + spdlog::error("Failed to enumerate adapters"); pFactory->Release(); return Error(); } DXGI_ADAPTER_DESC1 adapterDesc; if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { - log("Failed to get adapter description"); + spdlog::error("Failed to get adapter description"); pAdapter->Release(); pFactory->Release(); return Error(); @@ -87,7 +87,7 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { std::string error = fromErrorNr(status); - log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); + spdlog::error("NvAPI_GetErrorMessage gave this error: {}", error); tonvss(szMsg, error); return Ok(); } @@ -323,17 +323,17 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { if (!pDev) return Error(); - log(std::format("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID)); + spdlog::debug("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID); lowlatency_ctx.init_al2(pDev); switch (pSetLatencyMarkerParams->markerType) { case SIMULATION_START: if (lowlatency_ctx.call_spot != SimulationStart) break; - log(std::format("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update())); + spdlog::debug("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update()); break; case INPUT_SAMPLE: if (lowlatency_ctx.call_spot == SleepCall) break; lowlatency_ctx.call_spot = InputSample; - log(std::format("LowLatency update called on input sample with result: {}", lowlatency_ctx.update())); + spdlog::debug("LowLatency update called on input sample with result: {}", lowlatency_ctx.update()); break; case PRESENT_START: if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); @@ -347,7 +347,7 @@ namespace nvd { return Error(); lowlatency_ctx.init_al2(pDevice); lowlatency_ctx.call_spot = SleepCall; - log(std::format("LowLatency update called on sleep with result: {}", lowlatency_ctx.update())); + spdlog::debug("LowLatency update called on sleep with result: {}", lowlatency_ctx.update()); return Ok(); } @@ -468,13 +468,13 @@ namespace nvd { d3dGeoDesc.AABBs = nvGeoDesc.aabbs; break; case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this - log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); + spdlog::error("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); return false; case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this - log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); + spdlog::error("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); return false; default: - log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); + spdlog::error("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); return false; } } @@ -546,7 +546,7 @@ namespace nvd { if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id == current_frame_id); previous_frame_id = current_frame_id; } - log(std::format("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID)); + spdlog::debug("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID); return Ok(); } @@ -569,14 +569,13 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { - log(std::format("Missing setting: {}", settingId)); + spdlog::debug("Missing get setting: {}", settingId); return Ok(); } NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { - log("NvAPI_DRS_SetSetting"); - log(std::format("\tsettingId: {}", pSetting->settingId)); - return NVAPI_OK; + spdlog::debug("Missing set setting: {}", pSetting->settingId); + return Ok(); } NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index d2cb696e..67839a7e 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -1,24 +1,5 @@ #include "log.h" -std::ostream null(nullptr); -std::ostream* logStream = &null; -std::ofstream fileStream; - -inline std::string getCurrentTimeFormatted() { - auto now = std::chrono::system_clock::now(); - auto now_t = std::chrono::system_clock::to_time_t(now); - auto now_tm = *std::localtime(&now_t); - auto now_duration = now - std::chrono::system_clock::from_time_t(std::mktime(&now_tm)); - auto now_us = std::chrono::duration_cast(now_duration); - std::ostringstream oss; - oss << std::setfill('0') << std::setw(2) << now_tm.tm_hour << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_min << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_sec << "." - << std::setfill('0') << std::setw(6) << now_us.count(); - - return oss.str(); -} - inline std::string extractFunctionName(const std::string& signature) { size_t start = signature.find("nvd::"); if (start == std::string::npos) return {}; @@ -29,39 +10,34 @@ inline std::string extractFunctionName(const std::string& signature) { return signature.substr(start, end - start); } -void log(const std::string& log) { - if (logStream == &null) return; - std::ostringstream oss; - oss << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; - *logStream << oss.str(); -} - NvAPI_Status Ok(const std::source_location& location) { - if (logStream != &null) - log(std::format("{}: {}", extractFunctionName(location.function_name()), "OK")); + spdlog::trace("{}: {}", extractFunctionName(location.function_name()), "OK"); return NVAPI_OK; } NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { - if (logStream != &null) - log(std::format("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status))); + spdlog::trace("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status)); return status; } -void prepareLogging(std::optional fileName) { - if (fileName.has_value()) { - fileStream.open(fileName.value(), std::ios_base::out | std::ios_base::app); - if (fileStream.is_open()) { - logStream = &fileStream; - return; - } - else { - std::cerr << "Failed to open log file: " << fileName.value() << std::endl; +void prepareLogging(spdlog::level::level_enum level) { + try { + if (level != spdlog::level::off) { + auto logger = spdlog::basic_logger_mt("basic_logger", "nvapi-dummy.log"); + spdlog::set_default_logger(logger); + if (level == spdlog::level::trace) + spdlog::set_pattern("[%H:%M:%S.%f] [%L] [thread %t] %v"); + else + spdlog::set_pattern("[%H:%M:%S.%f] [%L] %v"); + spdlog::set_level(level); + spdlog::flush_on(level); } + } catch (const spdlog::spdlog_ex &ex) { + std::cout << "Log init failed: " << ex.what() << std::endl; } - // logStream = &std::cout; } void closeLogging() { - fileStream.close(); + spdlog::default_logger()->flush(); + spdlog::shutdown(); } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/log.h b/OptiScaler/nvapi/fakenvapi/log.h index 98151f6c..8e7ebf1d 100755 --- a/OptiScaler/nvapi/fakenvapi/log.h +++ b/OptiScaler/nvapi/fakenvapi/log.h @@ -8,10 +8,10 @@ #include #include "util.h" #include "../external/nvapi.h" +#include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" -std::string getCurrentTimeFormatted(); -void log(const std::string& log); NvAPI_Status Ok(const std::source_location &location = std::source_location::current()); NvAPI_Status Error(NvAPI_Status status = NVAPI_ERROR, const std::source_location &location = std::source_location::current()); -void prepareLogging(std::optional fileName); +void prepareLogging(spdlog::level::level_enum level); void closeLogging(); diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h index bc1fb4aa..436d6ee3 100644 --- a/OptiScaler/nvapi/fakenvapi/lowlatency.h +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -96,8 +96,8 @@ public: else mode = LatencyFlex; - log(std::format("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex")); - log(std::format("FG status: {}", fg ? "enabled" : "disabled")); + spdlog::debug("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex"); + spdlog::debug("FG status: {}", fg ? "enabled" : "disabled"); if (mode == AntiLag2) { #if _MSC_VER && _WIN64 @@ -110,7 +110,7 @@ public: #endif } else if (mode == LatencyFlex) { if (lfx_stats.needs_reset) { - log("LFX Reset"); + spdlog::info("LFX Reset"); lfx_stats.frame_id = 1; lfx_stats.needs_reset = false; lf->Reset(); @@ -122,7 +122,7 @@ public: lf->target_frame_time = 1000 * min_interval_us; lf->EndFrame(lfx_stats.frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); - log(std::format("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp)); + spdlog::debug("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp); lfx_stats.frame_id++; lfx_stats.target = lf->GetWaitTarget(lfx_stats.frame_id); @@ -174,8 +174,10 @@ public: } void set_min_interval_us(unsigned long interval_us) { - log(std::format("Max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0)); - min_interval_us = interval_us; + if (min_interval_us != interval_us) { + min_interval_us = interval_us; + spdlog::info("Changed max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0); + } } Mode get_mode() { diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index 2b97023c..bd14cf17 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -25,10 +25,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH: if ((logEnv && *logEnv == '1') || force_log) - prepareLogging("nvapi-dummy.log"); + prepareLogging(spdlog::level::trace); else - prepareLogging(std::nullopt); - log("--------------"); + prepareLogging(spdlog::level::off); + spdlog::critical("----------------"); break; case DLL_PROCESS_DETACH: closeLogging(); @@ -74,7 +74,7 @@ namespace nvd { [id](const auto& item) { return item.id == id; }); if (it == std::end(extended_interface_table)) { - log(std::format("NvAPI_QueryInterface (0x{:x}): Unknown interface ID", id)); + spdlog::debug("NvAPI_QueryInterface (0x{:x}): Unknown interface ID", id); return registry.insert({ id, nullptr }).first->second; } @@ -138,7 +138,7 @@ namespace nvd { INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unload) INSERT_AND_RETURN_WHEN_EQUALS(Dummy_GetLatency) - log(std::format("{}: not implemented, placeholder given", it->func)); + spdlog::debug("{}: not implemented, placeholder given", it->func); return registry.insert({ id, (void*)placeholder }).first->second; // return registry.insert({ id, nullptr }).first->second; } diff --git a/OptiScaler/nvapi/fakenvapi/meson.build b/OptiScaler/nvapi/fakenvapi/meson.build index 83e0fc7a..bcddfa1b 100644 --- a/OptiScaler/nvapi/fakenvapi/meson.build +++ b/OptiScaler/nvapi/fakenvapi/meson.build @@ -3,5 +3,6 @@ dll = shared_library( ['main.cpp', 'fakenvapi.cpp', 'util.cpp', 'log.cpp'], name_prefix : '', dependencies : [ lib_dxgi ], + include_directories: [ spdlog_headers ], install: true ) From d16b83486c7e40d3c5019a1fd10d9d6a1a02208e Mon Sep 17 00:00:00 2001 From: FakeMichau <49685661+FakeMichau@users.noreply.github.com> Date: Fri, 13 Sep 2024 00:58:22 +0200 Subject: [PATCH 18/18] Rename the project --- OptiScaler/nvapi/fakenvapi/log.cpp | 2 +- OptiScaler/nvapi/fakenvapi/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 67839a7e..6b530ecf 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -23,7 +23,7 @@ NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { void prepareLogging(spdlog::level::level_enum level) { try { if (level != spdlog::level::off) { - auto logger = spdlog::basic_logger_mt("basic_logger", "nvapi-dummy.log"); + auto logger = spdlog::basic_logger_mt("basic_logger", "fakenvapi.log"); spdlog::set_default_logger(logger); if (level == spdlog::level::trace) spdlog::set_pattern("[%H:%M:%S.%f] [%L] [thread %t] %v"); diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index bd14cf17..d28b3342 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -16,7 +16,7 @@ #include "log.h" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - auto logEnv = std::getenv("NVAPI_LOG"); + auto logEnv = std::getenv("FAKENVAPI_LOG"); #ifdef TESTING bool force_log = true; #else