├── .github └── workflows │ ├── build.yml │ └── build_windows.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── build-win32.txt ├── build-win64.txt ├── build.bat ├── convert_log.py ├── external ├── d3d12.h ├── ffx_antilag2_dx11.h ├── ffx_antilag2_dx12.h ├── latencyflex.h ├── nvapi.h └── nvapi_interface.h ├── fakenvapi.ini ├── meson.build ├── package-release.sh ├── resource.rc.in ├── src ├── config.h ├── fakenvapi.cpp ├── fakenvapi.h ├── log.cpp ├── log.h ├── lowlatency.h ├── main.cpp ├── meson.build ├── util.cpp └── util.h └── version.h.in /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build on Linux 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build-linux: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v4 12 | with: 13 | submodules: recursive 14 | fetch-depth: 0 15 | 16 | - name: Build 17 | uses: Joshua-Ashton/arch-mingw-github-action@9cdb815264bce7a6346927521b176f578982679d 18 | with: 19 | command: | 20 | ./package-release.sh master build 21 | 22 | - name: Create tarball 23 | run: tar cvfz "fakenvapi.tar.gz" -C "./build/fakenvapi-master" . 24 | 25 | - name: Upload artifacts 26 | uses: actions/upload-artifact@v4 27 | with: 28 | name: fakenvapi-${{ github.ref_name }} 29 | path: build/fakenvapi-master 30 | -------------------------------------------------------------------------------- /.github/workflows/build_windows.yml: -------------------------------------------------------------------------------- 1 | name: Build on Windows 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | build-windows: 8 | runs-on: windows-2022 9 | steps: 10 | - name: Checkout code 11 | uses: actions/checkout@v4 12 | with: 13 | submodules: recursive 14 | fetch-depth: 0 15 | 16 | - name: Setup Meson 17 | shell: pwsh 18 | run: pip install meson 19 | 20 | - name: Find Visual Studio 21 | shell: pwsh 22 | run: | 23 | $installationPath = Get-VSSetupInstance ` 24 | | Select-VSSetupInstance -Require Microsoft.VisualStudio.Workload.NativeDesktop -Latest ` 25 | | Select-Object -ExpandProperty InstallationPath 26 | Write-Output "VSDEVCMD=${installationPath}\Common7\Tools\VsDevCmd.bat" ` 27 | | Out-File -FilePath "${Env:GITHUB_ENV}" -Append 28 | 29 | - name: Build MSVC x86 30 | shell: pwsh 31 | run: | 32 | & "${Env:COMSPEC}" /s /c "`"${Env:VSDEVCMD}`" -arch=x86 -host_arch=x64 -no_logo && set" ` 33 | | % { , ($_ -Split '=', 2) } ` 34 | | % { [System.Environment]::SetEnvironmentVariable($_[0], $_[1]) } 35 | meson setup --buildtype release --backend vs2022 --default-library both --wipe build-msvc-x86 36 | meson compile -C build-msvc-x86 37 | 38 | - name: Build MSVC x64 39 | shell: pwsh 40 | run: | 41 | & "${Env:COMSPEC}" /s /c "`"${Env:VSDEVCMD}`" -arch=x64 -host_arch=x64 -no_logo && set" ` 42 | | % { , ($_ -Split '=', 2) } ` 43 | | % { [System.Environment]::SetEnvironmentVariable($_[0], $_[1]) } 44 | meson setup --buildtype release --backend vs2022 --default-library both --wipe build-msvc-x64 45 | meson compile -C build-msvc-x64 46 | 47 | - name: Prepare files 48 | shell: pwsh 49 | run: | 50 | mkdir x86 51 | cp build-msvc-x86/src/nvapi.dll x86 52 | mkdir x64 53 | cp build-msvc-x64/src/nvapi64.dll x64 54 | 55 | - name: Upload artifacts 56 | uses: actions/upload-artifact@v4 57 | with: 58 | name: fakenvapi-${{ github.ref_name }} 59 | path: | 60 | x86/ 61 | x64/ 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | testing/ 3 | useful/ 4 | .vscode/ 5 | .vs/ 6 | build_testing.bat 7 | testing.sh -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/spdlog"] 2 | path = external/spdlog 3 | url = https://github.com/gabime/spdlog.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Michał Lewandowski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Project inspired by/based on [dxvk-nvapi](https://github.com/jp7677/dxvk-nvapi/) 2 | 3 | By default logging is disabled. To enable logging put [fakenvapi.ini](fakenvapi.ini) next to the exe and edit the config 4 | 5 | # Installation 6 | **Do not use on Nvidia cards unless you know what you are doing** 7 | 8 | Best to use [OptiScaler](https://github.com/cdozdil/OptiScaler/blob/master/Spoofing.md#nvapi) as a loader for fakenvapi and all the required GPU spoofing. 9 | 10 | Just put `nvapi64.dll` next to OptiScaler's dll and fakenvapi will be automatically loaded. If it doesn't then set ``OverrideNvapiDll=true`` in Optiscaler's config file. 11 | 12 | # Overview 13 | Supports [LatencyFlex](https://github.com/ishitatsuyuki/LatencyFleX) as well as [AntiLag 2](https://github.com/GPUOpen-LibrariesAndSDKs/AntiLag2-SDK). 14 | AntiLag 2 is automatically selected when available. 15 | 16 | AL2 can't be used with native FSR FG as DLSSG-specific Reflex calls are required. LatencyFlex can be used in that case but it will require [forcing it](https://github.com/FakeMichau/fakenvapi/blob/master/fakenvapi.ini#L7C1-L7C18) using the ini file on AL2-supported systems. 17 | 18 | Benefits of AntiLag 2: 19 | - Good reduction in latency 20 | - Overlay indicating that it's working - frame delay should be green 21 | 22 | Downsides of AntiLag 2: 23 | - Limited to AMD RDNA1+ cards and Windows 24 | - Unreliable overlay readings. More accurate values are given by [FrameView](https://www.nvidia.com/en-us/geforce/technologies/frameview/) and looking at PCL. Fail safe way of confirming the latency is using [FLM](https://github.com/GPUOpen-Tools/frame_latency_meter/releases) 25 | - Currently can only be built using MSVC and not MinGW 26 |   27 | 28 | Benefits of LatencyFlex: 29 | - Crossplatform, crossvendor 30 | - Open source 31 | 32 | Downsides of LatencyFlex: 33 | - Limited latency reduction compared to AL2 34 | - Low fps just after launching a game that stabilizes over time 35 | -------------------------------------------------------------------------------- /build-win32.txt: -------------------------------------------------------------------------------- 1 | [binaries] 2 | cpp = 'i686-w64-mingw32-g++' 3 | strip = 'i686-w64-mingw32-strip' 4 | ar = 'i686-w64-mingw32-ar' 5 | windres = 'i686-w64-mingw32-windres' 6 | 7 | [built-in options] 8 | cpp_args=['-msse', '-msse2'] 9 | cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] 10 | 11 | [properties] 12 | needs_exe_wrapper = true 13 | 14 | [host_machine] 15 | system = 'windows' 16 | cpu_family = 'x86' 17 | cpu = 'x86' 18 | endian = 'little' 19 | -------------------------------------------------------------------------------- /build-win64.txt: -------------------------------------------------------------------------------- 1 | [binaries] 2 | cpp = 'x86_64-w64-mingw32-g++' 3 | strip = 'x86_64-w64-mingw32-strip' 4 | ar = 'x86_64-w64-mingw32-ar' 5 | windres = 'x86_64-w64-mingw32-windres' 6 | 7 | [built-in options] 8 | cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++'] 9 | 10 | [properties] 11 | needs_exe_wrapper = true 12 | 13 | [host_machine] 14 | system = 'windows' 15 | cpu_family = 'x86_64' 16 | cpu = 'x86_64' 17 | endian = 'little' 18 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | meson setup --buildtype release --default-library both build --wipe 2 | meson compile -C build -------------------------------------------------------------------------------- /convert_log.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | 4 | def convert_timestamp_to_milliseconds(log_start, timestamp): 5 | timestamp = int(timestamp) / 1e6 6 | log_start = int(log_start) / 1e6 7 | return timestamp - log_start 8 | 9 | # Very crude, works for now 10 | def parse_log_line(line): 11 | parts = line.strip().split(',') 12 | if len(parts) >= 4 and parts[0].endswith("EVENT"): 13 | event_name = parts[1] 14 | timestamp = parts[2] 15 | extra_data = parts[3] 16 | return event_name, timestamp, extra_data 17 | return None 18 | 19 | def convert(log_file): 20 | event_pairs = { 21 | "lfx_beginframe": "lfx_endframe", 22 | "marker_SIMULATION_START": "marker_SIMULATION_END", 23 | "marker_RENDERSUBMIT_START": "marker_RENDERSUBMIT_END", 24 | "marker_PRESENT_START": "marker_PRESENT_END", 25 | "async_marker_PRESENT_START": "async_marker_PRESENT_START", 26 | "async_marker_OUB_RENDERSUBMIT_START": "async_marker_OUB_RENDERSUBMIT_END", 27 | "async_marker_OUB_PRESENT_START": "async_marker_OUB_PRESENT_END" 28 | } 29 | in_progress_events = {} 30 | events = [] 31 | 32 | with open(log_file, 'r') as file: 33 | log_lines = file.readlines() 34 | if not log_lines: 35 | return None 36 | 37 | # Find earliest timestamp 38 | first_event = None 39 | for line in log_lines: 40 | first_event = parse_log_line(line) 41 | if first_event: 42 | break 43 | 44 | if first_event is None: 45 | raise ValueError("No valid log lines found in the log file.") 46 | 47 | log_start_time = int(first_event[1]) 48 | 49 | for line in log_lines: 50 | parsed = parse_log_line(line) 51 | if parsed: 52 | event_name, timestamp, extra_data = parsed 53 | timestamp_ns = int(timestamp) 54 | time_in_us = (timestamp_ns - log_start_time) // 1000 55 | 56 | if event_name in event_pairs: 57 | if extra_data not in in_progress_events: 58 | in_progress_events[extra_data] = [] 59 | in_progress_events[extra_data].append((event_name, time_in_us)) 60 | elif event_name in event_pairs.values(): 61 | start_event_name = next((k for k, v in event_pairs.items() if v == event_name), None) 62 | if start_event_name and extra_data in in_progress_events: 63 | matching_event = next((evt for evt in in_progress_events[extra_data] if evt[0] == start_event_name), None) 64 | if matching_event: 65 | in_progress_events[extra_data].remove(matching_event) 66 | begin_time = matching_event[1] 67 | events.append({ 68 | "name": start_event_name.replace("_START", "").replace("begin", ""), 69 | "cat": "LatencyFlex" if "lfx" in start_event_name else "Marker", 70 | "ph": "X", 71 | "ts": begin_time, 72 | "dur": time_in_us - begin_time, 73 | "pid": 0, 74 | "args": { 75 | "frame_id": extra_data, 76 | } 77 | }) 78 | if not in_progress_events[extra_data]: 79 | del in_progress_events[extra_data] 80 | elif event_name == "lfx_sleep" or event_name == "al2_sleep": 81 | duration_us = int(extra_data) // 1000 82 | events.append({ 83 | "name": event_name, 84 | "cat": "LatencyFlex", 85 | "ph": "X", 86 | "ts": time_in_us, 87 | "dur": duration_us, 88 | "pid": 0 89 | }) 90 | else: 91 | events.append({ 92 | "name": event_name, 93 | "cat": "General", 94 | "ph": "i", 95 | "ts": time_in_us, 96 | "pid": 0, 97 | "args": { 98 | "frame_id": extra_data 99 | } 100 | }) 101 | return events 102 | 103 | def main(): 104 | if len(sys.argv) > 1: 105 | log_file = sys.argv[1] 106 | output_file = 'trace_events.json' 107 | 108 | trace_events = convert(log_file) 109 | if trace_events: 110 | with open(output_file, 'w') as file: 111 | json.dump({"traceEvents": trace_events}, file, indent=4) 112 | print("Trace event data saved to", output_file) 113 | else: 114 | print("No data to convert.") 115 | else: 116 | print("No path provided") 117 | 118 | if __name__ == "__main__": 119 | main() 120 | -------------------------------------------------------------------------------- /external/ffx_antilag2_dx11.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Anti-Lag 2.0 SDK. 2 | // 3 | // Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #pragma once 23 | 24 | #include 25 | 26 | namespace AMD { 27 | namespace AntiLag2DX11 { 28 | 29 | struct Context; 30 | 31 | // Initialize function - call this once before the Update function. 32 | // context - Declare a persistent Context variable in your game code. Ensure the contents are zero'ed, and pass the address in to initialize it. 33 | // Be sure to use the *same* context object everywhere when calling the Anti-Lag 2.0 SDK functions. 34 | // A return value of S_OK indicates that Anti-Lag 2.0 is available on the system. 35 | HRESULT Initialize( Context* context ); 36 | 37 | // DeInitialize function - call this on game exit. 38 | // context - address of the game's context object. 39 | // The return value is the reference count of the internal API. It should be 0. 40 | ULONG DeInitialize( Context* context ); 41 | 42 | // Update function - call this just before the input to the game is polled. 43 | // context - address of the game's context object. 44 | // enable - enables or disables Anti-Lag 2.0. 45 | // maxFPS - sets a framerate limit. Zero will disable the limiter. 46 | HRESULT Update( Context* context, bool enable, unsigned int maxFPS ); 47 | 48 | // 49 | // End of public API section. 50 | // Private implementation details below. 51 | // 52 | 53 | // Forward declaration of the Anti-Lag 2.0 interface into the DX11 driver 54 | class IAmdDxExtInterface 55 | { 56 | public: 57 | virtual unsigned int AddRef() = 0; 58 | virtual unsigned int Release() = 0; 59 | 60 | protected: 61 | IAmdDxExtInterface() {} // Default constructor disabled 62 | virtual ~IAmdDxExtInterface() = 0; 63 | }; 64 | 65 | inline IAmdDxExtInterface::~IAmdDxExtInterface() {} 66 | 67 | // Structure version 1 for Anti-Lag 2.0: 68 | struct APIData_v1 69 | { 70 | unsigned int uiSize; 71 | unsigned int uiVersion; 72 | unsigned int eMode; 73 | const char* sControlStr; 74 | unsigned int uiControlStrLength; 75 | unsigned int maxFPS; 76 | }; 77 | static_assert(sizeof(APIData_v1) == 32, "Check structure packing compiler settings."); 78 | 79 | // Forward declaration of the Anti-Lag interface into the DX11 driver 80 | struct IAmdDxExtAntiLagApi : public IAmdDxExtInterface 81 | { 82 | public: 83 | virtual HRESULT UpdateAntiLagStateDx11( APIData_v1* pApiCallbackData ) = 0; 84 | }; 85 | 86 | // Context structure for the SDK. Declare a persistent object of this type *once* in your game code. 87 | // Ensure the contents are initialized to zero before calling Initialize() but do not modify these members directly after that. 88 | struct Context 89 | { 90 | IAmdDxExtAntiLagApi* m_pAntiLagAPI = nullptr; 91 | bool m_enabled = false; 92 | unsigned int m_maxFPS = 0; 93 | }; 94 | 95 | inline HRESULT Initialize( Context* context ) 96 | { 97 | HRESULT hr = E_INVALIDARG; 98 | if ( context && context->m_pAntiLagAPI == nullptr ) 99 | { 100 | HMODULE hModule = GetModuleHandleA("amdxx64.dll"); // only 64 bit is supported 101 | if ( hModule ) 102 | { 103 | typedef HRESULT(__cdecl* PFNAmdDxExtCreate11)(ID3D11Device* pDevice, IAmdDxExtInterface** ppAntiLagApi); 104 | PFNAmdDxExtCreate11 AmdDxExtCreate11 = reinterpret_cast((VOID*)GetProcAddress(hModule, "AmdDxExtCreate11")); 105 | if ( AmdDxExtCreate11 ) 106 | { 107 | *(__int64*)&context->m_pAntiLagAPI = 0xbf380ebc5ab4d0a6; // sets up the request identifier 108 | hr = AmdDxExtCreate11( nullptr, (IAmdDxExtInterface**)&context->m_pAntiLagAPI ); 109 | if ( hr == S_OK ) 110 | { 111 | APIData_v1 data = {}; 112 | data.uiSize = sizeof(data); 113 | data.uiVersion = 1; 114 | data.eMode = 2; // Anti-Lag 2.0 is disabled during initialization 115 | data.sControlStr = nullptr; 116 | data.uiControlStrLength = 0; 117 | data.maxFPS = 0; 118 | 119 | hr = context->m_pAntiLagAPI->UpdateAntiLagStateDx11( &data ); 120 | } 121 | 122 | if ( hr != S_OK ) 123 | { 124 | DeInitialize( context ); 125 | } 126 | } 127 | } 128 | else 129 | { 130 | hr = E_HANDLE; 131 | } 132 | } 133 | return hr; 134 | } 135 | 136 | inline ULONG DeInitialize( Context* context ) 137 | { 138 | ULONG refCount = 0; 139 | if ( context ) 140 | { 141 | if ( context->m_pAntiLagAPI ) 142 | { 143 | refCount = context->m_pAntiLagAPI->Release(); 144 | context->m_pAntiLagAPI = nullptr; 145 | } 146 | context->m_enabled = false; 147 | } 148 | return refCount; 149 | } 150 | 151 | inline HRESULT Update( Context* context, bool enabled, unsigned int maxFPS ) 152 | { 153 | // This function needs to be called once per frame, before the user input 154 | // is sampled - or optionally also when the UI settings are modified. 155 | if ( context && context->m_pAntiLagAPI ) 156 | { 157 | // Update the Anti-Lag 2.0 internal state only when necessary: 158 | if ( context->m_enabled != enabled || context->m_maxFPS != maxFPS ) 159 | { 160 | context->m_enabled = enabled; 161 | context->m_maxFPS = maxFPS; 162 | 163 | APIData_v1 data = {}; 164 | data.uiSize = sizeof(data); 165 | data.uiVersion = 1; 166 | data.eMode = enabled ? 1 : 2; 167 | data.maxFPS = maxFPS; 168 | static const char params[] = "delag_next_osd_supported_in_dxxp = 1"; 169 | data.sControlStr = params; 170 | data.uiControlStrLength = _countof( params ) - 1; 171 | 172 | // Only call the function with non-null arguments when setting state. 173 | // Make sure not to set the state every frame. 174 | context->m_pAntiLagAPI->UpdateAntiLagStateDx11( &data ); 175 | } 176 | 177 | // Call the function with a nullptr to insert the latency-reducing delay. 178 | // (if the state has not been set to 'enabled' this call will have no effect) 179 | HRESULT hr = context->m_pAntiLagAPI->UpdateAntiLagStateDx11( nullptr ); 180 | if ( hr == S_OK || hr == S_FALSE ) 181 | { 182 | return S_OK; 183 | } 184 | else 185 | { 186 | return hr; 187 | } 188 | } 189 | else 190 | { 191 | return E_NOINTERFACE; 192 | } 193 | } 194 | 195 | } // namespace AntiLag2DX11 196 | } // namespace AMD -------------------------------------------------------------------------------- /external/ffx_antilag2_dx12.h: -------------------------------------------------------------------------------- 1 | // This file is part of the Anti-Lag 2.0 SDK. 2 | // 3 | // Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #pragma once 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifndef MIDL_INTERFACE 29 | #define MIDL_INTERFACE(x) struct __declspec(uuid(x)) __declspec(novtable) 30 | #endif 31 | 32 | DEFINE_GUID(IID_IAmdExtAntiLagApi, 33 | 0x44085fbe, 0xe839, 0x40c5, 0xbf, 0x38, 0x0e, 0xbc, 0x5a, 0xb4, 0xd0, 0xa6); 34 | 35 | namespace AMD { 36 | namespace AntiLag2DX12 { 37 | 38 | struct Context; 39 | 40 | // Initialize function - call this once before the Update function. 41 | // context - Declare a persistent Context variable in your game code. Ensure the contents are zero'ed, and pass the address in to initialize it. 42 | // Be sure to use the *same* context object everywhere when calling the Anti-Lag 2.0 SDK functions. 43 | // device - The game's D3D12 device. 44 | // A return value of S_OK indicates that Anti-Lag 2.0 is available on the system. 45 | HRESULT Initialize( Context* context, ID3D12Device* device ); 46 | 47 | // DeInitialize function - call this before destroying the device. 48 | // context - address of the game's context object. 49 | // The return value is the reference count of the internal API. It should be 0. 50 | ULONG DeInitialize( Context* context ); 51 | 52 | // Update function - call this just before the input to the game is polled. 53 | // context - address of the game's context object. 54 | // enable - enables or disables Anti-Lag 2.0. 55 | // maxFPS - sets a framerate limit. Zero will disable the limiter. 56 | HRESULT Update( Context* context, bool enable, unsigned int maxFPS ); 57 | 58 | // Call this on the game render thread once the game's main rendering workload has been submitted in an ExecuteCommandLists call. 59 | // Call before the FSR 3 Present call is made. 60 | // This is only required if frame generation is enabled, but calling it anyway is harmless. 61 | // context - address of the game's context object. 62 | HRESULT MarkEndOfFrameRendering( Context* context ); 63 | 64 | // Call this on the presentation thread just before the Present call. 65 | // This is only required if frame generation is enabled, but calling it anyway is harmless. 66 | // context - address of the game's context object. 67 | // bInterpolatedFrame - whether the frame about to be presented is interpolated. 68 | HRESULT SetFrameGenFrameType( Context* context, bool bInterpolatedFrame ); 69 | 70 | // 71 | // End of public API section. 72 | // Private implementation details below. 73 | // 74 | 75 | // Forward declaration of the Anti-Lag interface into the DX12 driver 76 | MIDL_INTERFACE("44085fbe-e839-40c5-bf38-0ebc5ab4d0a6") 77 | IAmdExtAntiLagApi: public IUnknown 78 | { 79 | public: 80 | virtual HRESULT UpdateAntiLagState(VOID* pData) = 0; 81 | }; 82 | 83 | // Context structure for the SDK. Declare a persistent object of this type *once* in your game code. 84 | // Ensure the contents are initialized to zero before calling Initialize() but do not modify these members directly after that. 85 | struct Context 86 | { 87 | IAmdExtAntiLagApi* m_pAntiLagAPI = nullptr; 88 | bool m_enabled = false; 89 | unsigned int m_maxFPS = 0; 90 | }; 91 | 92 | // Structure version 1 for Anti-Lag 2.0: 93 | struct APIData_v1 94 | { 95 | unsigned int uiSize; 96 | unsigned int uiVersion; 97 | unsigned int eMode; 98 | const char* sControlStr; 99 | unsigned int uiControlStrLength; 100 | unsigned int maxFPS; 101 | }; 102 | static_assert(sizeof(APIData_v1) == 32, "Check structure packing compiler settings."); 103 | 104 | // Structure version 2 for Anti-Lag 2.0: 105 | struct APIData_v2 106 | { 107 | unsigned int uiSize; 108 | unsigned int uiVersion; 109 | struct Flags 110 | { 111 | unsigned int unused0 : 1; 112 | unsigned int unused1 : 1; 113 | 114 | unsigned int signalFgFrameType : 1; 115 | unsigned int isInterpolatedFrame : 1; 116 | 117 | unsigned int signalGetUserInputIdx : 1; 118 | unsigned int signalEndOfFrameIdx : 1; 119 | 120 | unsigned int reserved :26; 121 | } flags; 122 | unsigned __int64 iiFrameIdx; 123 | unsigned __int64 uiiReserved[19]; 124 | }; 125 | static_assert(sizeof(APIData_v2) == 176, "Check structure packing compiler settings."); 126 | 127 | inline HRESULT Initialize( Context* context, ID3D12Device* device ) 128 | { 129 | HRESULT hr = E_INVALIDARG; 130 | if ( context && device && context->m_pAntiLagAPI == nullptr ) 131 | { 132 | HMODULE hModule = GetModuleHandleA("amdxc64.dll"); 133 | if ( hModule ) 134 | { 135 | typedef HRESULT(__cdecl* PFNAmdExtD3DCreateInterface)( IUnknown* pOuter, REFIID riid, void** ppvObject ); 136 | PFNAmdExtD3DCreateInterface AmdExtD3DCreateInterface = reinterpret_cast( (VOID*)GetProcAddress(hModule, "AmdExtD3DCreateInterface") ); 137 | if ( AmdExtD3DCreateInterface ) 138 | { 139 | hr = AmdExtD3DCreateInterface( device, IID_IAmdExtAntiLagApi, (void**)&context->m_pAntiLagAPI ); 140 | if ( hr == S_OK && context->m_pAntiLagAPI ) 141 | { 142 | APIData_v1 data = {}; 143 | data.uiSize = sizeof(data); 144 | data.uiVersion = 1; 145 | data.eMode = 2; // Anti-Lag 2.0 is disabled during initialization 146 | data.sControlStr = nullptr; 147 | data.uiControlStrLength = 0; 148 | data.maxFPS = 0; 149 | 150 | hr = context->m_pAntiLagAPI->UpdateAntiLagState( &data ); 151 | } 152 | 153 | if ( hr != S_OK ) 154 | { 155 | DeInitialize( context ); 156 | } 157 | } 158 | } 159 | else 160 | { 161 | hr = E_HANDLE; 162 | } 163 | } 164 | return hr; 165 | } 166 | 167 | inline ULONG DeInitialize( Context* context ) 168 | { 169 | ULONG refCount = 0; 170 | if ( context ) 171 | { 172 | if ( context->m_pAntiLagAPI ) 173 | { 174 | refCount = context->m_pAntiLagAPI->Release(); 175 | context->m_pAntiLagAPI = nullptr; 176 | } 177 | context->m_enabled = false; 178 | } 179 | 180 | return refCount; 181 | } 182 | 183 | inline HRESULT Update( Context* context, bool enabled, unsigned int maxFPS ) 184 | { 185 | // This function needs to be called once per frame, before the user input 186 | // is sampled - or optionally also when the UI settings are modified. 187 | if ( context && context->m_pAntiLagAPI ) 188 | { 189 | // Update the Anti-Lag 2.0 internal state only when necessary: 190 | if ( context->m_enabled != enabled || context->m_maxFPS != maxFPS ) 191 | { 192 | context->m_enabled = enabled; 193 | context->m_maxFPS = maxFPS; 194 | 195 | APIData_v1 data = {}; 196 | data.uiSize = sizeof(data); 197 | data.uiVersion = 1; 198 | data.eMode = enabled ? 1 : 2; 199 | data.sControlStr = nullptr; 200 | data.uiControlStrLength = 0; 201 | data.maxFPS = maxFPS; 202 | 203 | // Only call the function with non-null arguments when setting state. 204 | // Make sure not to set the state every frame. 205 | context->m_pAntiLagAPI->UpdateAntiLagState( &data ); 206 | } 207 | 208 | // Call the function with a nullptr to insert the latency-reducing delay. 209 | // (if the state has not been set to 'enabled' this call will have no effect) 210 | HRESULT hr = context->m_pAntiLagAPI->UpdateAntiLagState( nullptr ); 211 | if ( hr == S_OK || hr == S_FALSE ) 212 | { 213 | return S_OK; 214 | } 215 | else 216 | { 217 | return hr; 218 | } 219 | } 220 | else 221 | { 222 | return E_NOINTERFACE; 223 | } 224 | } 225 | 226 | // Internal helper function 227 | inline HRESULT SetFrameGenParamsInternal( Context* context, APIData_v2::Flags flags ) 228 | { 229 | if ( context && context->m_pAntiLagAPI ) 230 | { 231 | APIData_v2 data = {}; 232 | data.uiSize = sizeof(data); 233 | data.uiVersion = 2; 234 | data.flags = flags; 235 | data.iiFrameIdx = 0; 236 | 237 | return context->m_pAntiLagAPI->UpdateAntiLagState( &data ); 238 | } 239 | else 240 | { 241 | return E_NOINTERFACE; 242 | } 243 | } 244 | 245 | inline HRESULT MarkEndOfFrameRendering( Context* context ) 246 | { 247 | APIData_v2::Flags flags = {}; 248 | flags.signalEndOfFrameIdx = 1; 249 | return SetFrameGenParamsInternal( context, flags ); 250 | } 251 | 252 | inline HRESULT SetFrameGenFrameType( Context* context, bool bInterpolatedFrame ) 253 | { 254 | APIData_v2::Flags flags = {}; 255 | flags.signalFgFrameType = 1; 256 | flags.isInterpolatedFrame = bInterpolatedFrame ? 1 : 0; 257 | return SetFrameGenParamsInternal( context, flags ); 258 | } 259 | } // namespace AntiLag2DX12 260 | } // namespace AMD -------------------------------------------------------------------------------- /external/latencyflex.h: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tatsuyuki Ishi 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef LATENCYFLEX_H 16 | #define LATENCYFLEX_H 17 | 18 | // #include "log.h" 19 | 20 | #ifdef LATENCYFLEX_HAVE_PERFETTO 21 | #include 22 | PERFETTO_DEFINE_CATEGORIES( 23 | perfetto::Category("latencyflex").SetDescription("LatencyFleX latency and throughput metrics")); 24 | #else 25 | #define TRACE_COUNTER(...) 26 | // #define TRACE_COUNTER(a, b, c) spdlog::trace("{}: {}", b, c) 27 | #define TRACE_EVENT_BEGIN(...) 28 | #define TRACE_EVENT_END(...) 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #if defined __MINGW64__ || defined __MINGW32__ 40 | #define max(a, b) std::max(a, b) 41 | #endif 42 | 43 | namespace lfx { 44 | namespace internal { 45 | // An exponentially weighted moving average estimator. 46 | class EwmaEstimator { 47 | public: 48 | // `alpha`: Smoothing factor. Larger values means less smoothing, resulting in 49 | // a bumpy but quick response. 50 | // `full_weight`: Set to true to disable weight correction for initial 51 | // samples. The estimator will start with a value of 0 weighted 52 | // at 100% instead. 53 | EwmaEstimator(double alpha, bool full_weight = false) 54 | : alpha_(alpha), current_weight_(full_weight ? 1.0 : 0.0) {} 55 | 56 | // Update the estimate with `value`. `value` must not be negative. If a 57 | // negative exponent is used, then `value` must not be too small or the 58 | // internal accumulator will overflow. 59 | void update(double value) { 60 | current_ = (1 - alpha_) * current_ + alpha_ * value; 61 | current_weight_ = (1 - alpha_) * current_weight_ + alpha_; 62 | } 63 | 64 | double get() const { 65 | if (current_weight_ == 0) { 66 | return 0; 67 | } 68 | return current_ / current_weight_; 69 | } 70 | 71 | private: 72 | double alpha_; 73 | double current_ = 0; 74 | double current_weight_; 75 | }; 76 | } // namespace internal 77 | 78 | enum Phases { kUp = 0, kDown, kNumPhases }; 79 | 80 | // Tracks and computes frame time, latency and the desired sleep time before 81 | // next tick. All time is in nanoseconds. The clock domain doesn't matter as 82 | // long as it's a single consistent clock. 83 | // 84 | // Access must be externally synchronized. 85 | class LatencyFleX { 86 | public: 87 | LatencyFleX() : latency_(0.3), inv_throughtput_(0.3), proj_correction_(0.5, true) { 88 | std::fill(std::begin(frame_begin_ids_), std::end(frame_begin_ids_), UINT64_MAX); 89 | } 90 | 91 | // Get the desired wake-up time. Sleep until this time, then call `BeginFrame()`. This function 92 | // must be called *exactly once* before each call to `BeginFrame()`. Calling this the second time 93 | // with the same `frame_id` will corrupt the internal time tracking. 94 | // 95 | // If a wait target cannot be determined due to lack of data, then `0` is 96 | // returned. 97 | uint64_t GetWaitTarget(uint64_t frame_id) { 98 | if (prev_frame_end_id_ != UINT64_MAX) { 99 | size_t phase = frame_id % kNumPhases; 100 | double invtpt = inv_throughtput_.get(); 101 | int64_t comp_to_apply = 0; 102 | if (frame_end_projection_base_ == UINT64_MAX) { 103 | frame_end_projection_base_ = prev_frame_end_ts_; 104 | } else { 105 | // The prediction error is equal to (actual latency) - (expected latency). 106 | // As we adapt our latency estimator to the actual latency values, this 107 | // will eventually converge as long as we are not constantly overpacing, 108 | // building a queue at a faster pace than the estimator can adapt. 109 | 110 | // In the section below, we attempt to apply additional compensation in 111 | // the case of delay increase, to prevent extra queuing as much as possible. 112 | int64_t prediction_error = 113 | (int64_t)prev_frame_end_ts_ - 114 | (int64_t)(frame_end_projection_base_ + 115 | frame_end_projected_ts_[prev_frame_end_id_ % kMaxInflightFrames]); 116 | TRACE_COUNTER("latencyflex", "Prediction error", prediction_error); 117 | int64_t prev_comp_applied = comp_applied_[prev_frame_end_id_ % kMaxInflightFrames]; 118 | // We need to limit the compensation to delay increase, or otherwise we would cancel out the 119 | // regular delay decrease from our pacing. To achieve this, we treat any early prediction as 120 | // having prediction error of zero. 121 | // 122 | // We also want to cancel out the counter-reaction from our previous compensation, so what 123 | // we essentially want here is `prediction_error_ - prev_prediction_error_ + 124 | // prev_comp_applied`. But since we clamp prediction_error_ and prev_prediction_error_, 125 | // the naive approach of adding prev_comp_applied directly would have a bias toward 126 | // overcompensation. Consider the example below where we're pacing at the correct (100%) 127 | // rate but things arrives late due to reason that are *not* queuing (noise): 128 | // 5ms late, 5ms late, ... (a period longer than our latency) ... , 0ms 129 | // We would compensate -5ms on the first frame, bringing the prediction error to 0. But when 130 | // the 0ms frame arrives, the prediction error becomes -5ms due to our overcompensation. 131 | // Due to its negativity, we don't recompensate for this decrease: this is the bias. 132 | // 133 | // The solution here is to include prev_comp_applied as a part of clamping equation, which 134 | // allows it to also undercompensate when it makes sense. It seems to do a great job on 135 | // preventing prediction error from getting stuck in a state that is drift away. 136 | proj_correction_.update( 137 | max(INT64_C(0), prediction_error) - 138 | max(INT64_C(0), prev_prediction_error_ - prev_comp_applied)); 139 | prev_prediction_error_ = prediction_error; 140 | // Try to cancel out any unintended delay happened to previous frame start. This is 141 | // primarily meant for cases where a frame time spike happens and we get backpressured 142 | // on the main thread. prev_forced_correction_ will stay high until our prediction catches 143 | // up, canceling out any excessive correction we might end up doing. 144 | comp_to_apply = std::round(proj_correction_.get()); 145 | comp_applied_[frame_id % kMaxInflightFrames] = comp_to_apply; 146 | TRACE_COUNTER("latencyflex", "Delay Compensation", comp_to_apply); 147 | } 148 | 149 | // The target wakeup time. 150 | uint64_t target = 151 | (int64_t)frame_end_projection_base_ + 152 | (int64_t)frame_end_projected_ts_[prev_frame_begin_id_ % kMaxInflightFrames] + 153 | comp_to_apply + 154 | (int64_t)std::round((((int64_t)frame_id - (int64_t)prev_frame_begin_id_) + 155 | 1 / (phase == kUp ? up_factor_ : 1) - 1) * 156 | invtpt / down_factor_ - 157 | latency_.get()); 158 | // The projection is something close to the predicted frame end time, but it is always paced 159 | // at down_factor * throughput, which prevents delay compensation from kicking in until it's 160 | // actually necessary (i.e. we're overpacing). 161 | uint64_t new_projection = 162 | (int64_t)frame_end_projected_ts_[prev_frame_begin_id_ % kMaxInflightFrames] + 163 | comp_to_apply + 164 | (int64_t)std::round(((int64_t)frame_id - (int64_t)prev_frame_begin_id_) * invtpt / 165 | down_factor_); 166 | frame_end_projected_ts_[frame_id % kMaxInflightFrames] = new_projection; 167 | TRACE_EVENT_BEGIN( 168 | "latencyflex", "projection", 169 | perfetto::Track(track_base_ + frame_id % kMaxInflightFrames + kMaxInflightFrames), 170 | target); 171 | TRACE_EVENT_END( 172 | "latencyflex", 173 | perfetto::Track(track_base_ + frame_id % kMaxInflightFrames + kMaxInflightFrames), 174 | frame_end_projection_base_ + new_projection); 175 | return target; 176 | } else { 177 | return 0; 178 | } 179 | } 180 | 181 | // Begin the frame. Called on the main/simulation thread. 182 | // 183 | // This call must be preceded with a call to `GetWaitTarget()`. 184 | // 185 | // `target` should be the timestamp returned by `GetWaitTarget()`. 186 | // `timestamp` should be calculated as follows: 187 | // - If a sleep is not performed (because the wait target has already been 188 | // passed), then pass the current time. 189 | // - If a sleep is performed (wait target was not in the past), then pass the 190 | // wait target as-is. This allows compensating for any latency incurred by 191 | // the OS for waking up the process. 192 | void BeginFrame(uint64_t frame_id, uint64_t target, uint64_t timestamp) { 193 | TRACE_EVENT_BEGIN("latencyflex", "frame", 194 | perfetto::Track(track_base_ + frame_id % kMaxInflightFrames), timestamp); 195 | frame_begin_ids_[frame_id % kMaxInflightFrames] = frame_id; 196 | TRACE_COUNTER("latencyflex", "frame_id_begin", frame_id); 197 | frame_begin_ts_[frame_id % kMaxInflightFrames] = timestamp; 198 | prev_frame_begin_id_ = frame_id; 199 | if (target != 0) { 200 | int64_t forced_correction = timestamp - target; 201 | frame_end_projected_ts_[frame_id % kMaxInflightFrames] += forced_correction; 202 | comp_applied_[frame_id % kMaxInflightFrames] += forced_correction; 203 | prev_prediction_error_ += forced_correction; 204 | } 205 | } 206 | 207 | // End the frame. Called from a rendering-related thread. 208 | // 209 | // The timestamp should be obtained in one of the following ways: 210 | // - Run a thread dedicated to wait for command buffer completion fences. 211 | // Capture the timestamp on CPU when the fence is signaled. 212 | // - Capture a GPU timestamp when frame ends, then convert it into a clock 213 | // domain on CPU (known as "timestamp calibration"). 214 | // 215 | // If `latency` and `frame_time` are not null, then the latency and the frame 216 | // time are returned respectively, or UINT64_MAX is returned if measurement is 217 | // unavailable. 218 | void EndFrame(uint64_t frame_id, uint64_t timestamp, uint64_t *latency, uint64_t *frame_time) { 219 | size_t phase = frame_id % kNumPhases; 220 | int64_t latency_val = -1; 221 | int64_t frame_time_val = -1; 222 | TRACE_COUNTER("latencyflex", "frame_id_end", frame_id); 223 | if (frame_begin_ids_[frame_id % kMaxInflightFrames] == frame_id) { 224 | frame_begin_ids_[frame_id % kMaxInflightFrames] = UINT64_MAX; 225 | 226 | if (frame_time && prev_frame_end_id_ != UINT64_MAX) 227 | *frame_time = timestamp - prev_frame_real_end_ts_; 228 | prev_frame_real_end_ts_ = timestamp; 229 | timestamp = max(timestamp, prev_frame_end_ts_ + target_frame_time); 230 | auto frame_start = frame_begin_ts_[frame_id % kMaxInflightFrames]; 231 | latency_val = (int64_t)timestamp - (int64_t)frame_start; 232 | if (phase == kDown) { 233 | latency_.update(latency_val); 234 | } 235 | if (latency) 236 | *latency = latency_val; 237 | TRACE_COUNTER("latencyflex", "Latency", latency_val); 238 | TRACE_COUNTER("latencyflex", "Latency (Estimate)", latency_.get()); 239 | if (prev_frame_end_id_ != UINT64_MAX) { 240 | if (frame_id > prev_frame_end_id_) { 241 | auto frames_elapsed = frame_id - prev_frame_end_id_; 242 | frame_time_val = 243 | ((int64_t)timestamp - (int64_t)prev_frame_end_ts_) / (int64_t)frames_elapsed; 244 | frame_time_val = std::clamp(frame_time_val, INT64_C(1000000), INT64_C(50000000)); 245 | if (phase == kUp) { 246 | inv_throughtput_.update(frame_time_val); 247 | } 248 | TRACE_COUNTER("latencyflex", "Frame Time", frame_time_val); 249 | TRACE_COUNTER("latencyflex", "Frame Time (Estimate)", inv_throughtput_.get()); 250 | } 251 | } 252 | prev_frame_end_id_ = frame_id; 253 | prev_frame_end_ts_ = timestamp; 254 | } 255 | if (frame_time) 256 | *frame_time = frame_time_val; 257 | TRACE_EVENT_END("latencyflex", perfetto::Track(track_base_ + frame_id % kMaxInflightFrames), 258 | timestamp); 259 | } 260 | 261 | void Reset() { 262 | auto new_instance = LatencyFleX(); 263 | #ifdef LATENCYFLEX_HAVE_PERFETTO 264 | new_instance.track_base_ = track_base_ + 2 * kMaxInflightFrames; 265 | #endif 266 | new_instance.target_frame_time = target_frame_time; 267 | *this = new_instance; 268 | } 269 | 270 | uint64_t target_frame_time = 0; 271 | 272 | private: 273 | static const std::size_t kMaxInflightFrames = 16; 274 | 275 | uint64_t frame_begin_ts_[kMaxInflightFrames] = {}; 276 | uint64_t frame_begin_ids_[kMaxInflightFrames]; 277 | uint64_t frame_end_projected_ts_[kMaxInflightFrames] = {}; 278 | uint64_t frame_end_projection_base_ = UINT64_MAX; 279 | int64_t comp_applied_[kMaxInflightFrames] = {}; 280 | uint64_t prev_frame_begin_id_ = UINT64_MAX; 281 | double up_factor_ = 1.10; 282 | double down_factor_ = 0.985; 283 | int64_t prev_prediction_error_ = 0; 284 | uint64_t prev_frame_end_id_ = UINT64_MAX; 285 | uint64_t prev_frame_end_ts_ = 0; 286 | uint64_t prev_frame_real_end_ts_ = 0; 287 | internal::EwmaEstimator latency_; 288 | internal::EwmaEstimator inv_throughtput_; 289 | internal::EwmaEstimator proj_correction_; 290 | 291 | #ifdef LATENCYFLEX_HAVE_PERFETTO 292 | uint64_t track_base_ = 0; 293 | #endif 294 | }; 295 | } // namespace lfx 296 | #undef max 297 | #endif // LATENCYFLEX_H 298 | -------------------------------------------------------------------------------- /external/nvapi_interface.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | |* *| 3 | |* Copyright (c) 2019-2023, NVIDIA CORPORATION. All rights reserved. *| 4 | |* *| 5 | |* Permission is hereby granted, free of charge, to any person obtaining a *| 6 | |* copy of this software and associated documentation files (the "Software"), *| 7 | |* to deal in the Software without restriction, including without limitation *| 8 | |* the rights to use, copy, modify, merge, publish, distribute, sublicense, *| 9 | |* and/or sell copies of the Software, and to permit persons to whom the *| 10 | |* Software is furnished to do so, subject to the following conditions: *| 11 | |* *| 12 | |* The above copyright notice and this permission notice shall be included in *| 13 | |* all copies or substantial portions of the Software. *| 14 | |* *| 15 | |* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *| 16 | |* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *| 17 | |* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *| 18 | |* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *| 19 | |* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *| 20 | |* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *| 21 | |* DEALINGS IN THE SOFTWARE. *| 22 | |* *| 23 | |* *| 24 | \*****************************************************************************/ 25 | #ifndef _NVAPI_INTERFACE_H 26 | #define _NVAPI_INTERFACE_H 27 | 28 | struct NVAPI_INTERFACE_TABLE { const char * func; unsigned int id; }; 29 | struct NVAPI_INTERFACE_TABLE nvapi_interface_table[] = 30 | { 31 | { "NvAPI_Initialize", 0x0150e828 }, 32 | { "NvAPI_Unload", 0xd22bdd7e }, 33 | { "NvAPI_GetErrorMessage", 0x6c2d048c }, 34 | { "NvAPI_GetInterfaceVersionString", 0x01053fa5 }, 35 | { "NvAPI_GPU_GetEDID", 0x37d32e69 }, 36 | { "NvAPI_SetView", 0x0957d7b6 }, 37 | { "NvAPI_SetViewEx", 0x06b89e68 }, 38 | { "NvAPI_GetDisplayDriverVersion", 0xf951a4d1 }, 39 | { "NvAPI_SYS_GetDriverAndBranchVersion", 0x2926aaad }, 40 | { "NvAPI_GPU_GetMemoryInfo", 0x07f9b368 }, 41 | { "NvAPI_GPU_GetMemoryInfoEx", 0xc0599498 }, 42 | { "NvAPI_OGL_ExpertModeSet", 0x3805ef7a }, 43 | { "NvAPI_OGL_ExpertModeGet", 0x22ed9516 }, 44 | { "NvAPI_OGL_ExpertModeDefaultsSet", 0xb47a657e }, 45 | { "NvAPI_OGL_ExpertModeDefaultsGet", 0xae921f12 }, 46 | { "NvAPI_EnumPhysicalGPUs", 0xe5ac921f }, 47 | { "NvAPI_EnumTCCPhysicalGPUs", 0xd9930b07 }, 48 | { "NvAPI_EnumLogicalGPUs", 0x48b3ea59 }, 49 | { "NvAPI_GetPhysicalGPUsFromDisplay", 0x34ef9506 }, 50 | { "NvAPI_GetPhysicalGPUFromUnAttachedDisplay", 0x5018ed61 }, 51 | { "NvAPI_GetLogicalGPUFromDisplay", 0xee1370cf }, 52 | { "NvAPI_GetLogicalGPUFromPhysicalGPU", 0xadd604d1 }, 53 | { "NvAPI_GetPhysicalGPUsFromLogicalGPU", 0xaea3fa32 }, 54 | { "NvAPI_GetPhysicalGPUFromGPUID", 0x5380ad1a }, 55 | { "NvAPI_GetGPUIDfromPhysicalGPU", 0x6533ea3e }, 56 | { "NvAPI_GPU_GetShaderSubPipeCount", 0x0be17923 }, 57 | { "NvAPI_GPU_GetGpuCoreCount", 0xc7026a87 }, 58 | { "NvAPI_GPU_GetAllOutputs", 0x7d554f8e }, 59 | { "NvAPI_GPU_GetConnectedOutputs", 0x1730bfc9 }, 60 | { "NvAPI_GPU_GetConnectedSLIOutputs", 0x0680de09 }, 61 | { "NvAPI_GPU_GetConnectedDisplayIds", 0x0078dba2 }, 62 | { "NvAPI_GPU_GetAllDisplayIds", 0x785210a2 }, 63 | { "NvAPI_GPU_GetConnectedOutputsWithLidState", 0xcf8caf39 }, 64 | { "NvAPI_GPU_GetConnectedSLIOutputsWithLidState", 0x96043cc7 }, 65 | { "NvAPI_GPU_GetSystemType", 0xbaaabfcc }, 66 | { "NvAPI_GPU_GetActiveOutputs", 0xe3e89b6f }, 67 | { "NvAPI_GPU_SetEDID", 0xe83d6456 }, 68 | { "NvAPI_GPU_GetOutputType", 0x40a505e4 }, 69 | { "NvAPI_GPU_ValidateOutputCombination", 0x34c9c2d4 }, 70 | { "NvAPI_GPU_GetFullName", 0xceee8e9f }, 71 | { "NvAPI_GPU_GetPCIIdentifiers", 0x2ddfb66e }, 72 | { "NvAPI_GPU_GetGPUType", 0xc33baeb1 }, 73 | { "NvAPI_GPU_GetBusType", 0x1bb18724 }, 74 | { "NvAPI_GPU_GetBusId", 0x1be0b8e5 }, 75 | { "NvAPI_GPU_GetBusSlotId", 0x2a0a350f }, 76 | { "NvAPI_GPU_GetIRQ", 0xe4715417 }, 77 | { "NvAPI_GPU_GetVbiosRevision", 0xacc3da0a }, 78 | { "NvAPI_GPU_GetVbiosOEMRevision", 0x2d43fb31 }, 79 | { "NvAPI_GPU_GetVbiosVersionString", 0xa561fd7d }, 80 | { "NvAPI_GPU_GetAGPAperture", 0x6e042794 }, 81 | { "NvAPI_GPU_GetCurrentAGPRate", 0xc74925a0 }, 82 | { "NvAPI_GPU_GetCurrentPCIEDownstreamWidth", 0xd048c3b1 }, 83 | { "NvAPI_GPU_GetPhysicalFrameBufferSize", 0x46fbeb03 }, 84 | { "NvAPI_GPU_GetVirtualFrameBufferSize", 0x5a04b644 }, 85 | { "NvAPI_GPU_GetQuadroStatus", 0xe332fa47 }, 86 | { "NvAPI_GPU_GetBoardInfo", 0x22d54523 }, 87 | { "NvAPI_GPU_GetRamBusWidth", 0x7975c581 }, 88 | { "NvAPI_GPU_GetArchInfo", 0xd8265d24 }, 89 | { "NvAPI_I2CRead", 0x2fde12c5 }, 90 | { "NvAPI_I2CWrite", 0xe812eb07 }, 91 | { "NvAPI_GPU_WorkstationFeatureSetup", 0x6c1f3fe4 }, 92 | { "NvAPI_GPU_WorkstationFeatureQuery", 0x004537df }, 93 | { "NvAPI_GPU_GetHDCPSupportStatus", 0xf089eef5 }, 94 | { "NvAPI_GPU_CudaEnumComputeCapableGpus", 0x5786cc6e }, 95 | { "NvAPI_GPU_GetTachReading", 0x5f608315 }, 96 | { "NvAPI_GPU_GetECCStatusInfo", 0xca1ddaf3 }, 97 | { "NvAPI_GPU_GetECCErrorInfo", 0xc71f85a6 }, 98 | { "NvAPI_GPU_ResetECCErrorInfo", 0xc02eec20 }, 99 | { "NvAPI_GPU_GetECCConfigurationInfo", 0x77a796f3 }, 100 | { "NvAPI_GPU_SetECCConfiguration", 0x1cf639d9 }, 101 | { "NvAPI_GPU_QueryWorkstationFeatureSupport", 0x80b1abb9 }, 102 | { "NvAPI_GPU_SetScanoutIntensity", 0xa57457a4 }, 103 | { "NvAPI_GPU_GetScanoutIntensityState", 0xe81ce836 }, 104 | { "NvAPI_GPU_SetScanoutWarping", 0xb34bab4f }, 105 | { "NvAPI_GPU_GetScanoutWarpingState", 0x6f5435af }, 106 | { "NvAPI_GPU_SetScanoutCompositionParameter", 0xf898247d }, 107 | { "NvAPI_GPU_GetScanoutCompositionParameter", 0x58fe51e6 }, 108 | { "NvAPI_GPU_GetScanoutConfiguration", 0x6a9f5b63 }, 109 | { "NvAPI_GPU_GetScanoutConfigurationEx", 0xe2e1e6f0 }, 110 | { "NvAPI_GPU_GetAdapterIdFromPhysicalGpu", 0x0ff07fde }, 111 | { "NvAPI_GPU_GetVirtualizationInfo", 0x44e022a9 }, 112 | { "NvAPI_GPU_GetLogicalGpuInfo", 0x842b066e }, 113 | { "NvAPI_GPU_GetLicensableFeatures", 0x3fc596aa }, 114 | { "NvAPI_GPU_NVLINK_GetCaps", 0xbef1119d }, 115 | { "NvAPI_GPU_NVLINK_GetStatus", 0xc72a38e3 }, 116 | { "NvAPI_GPU_GetGPUInfo", 0xafd1b02c }, 117 | { "NvAPI_GPU_GetVRReadyData", 0x81d629c5 }, 118 | { "NvAPI_GPU_GetPerfDecreaseInfo", 0x7f7f4600 }, 119 | { "NvAPI_GPU_GetPstatesInfoEx", 0x843c0256 }, 120 | { "NvAPI_GPU_GetPstates20", 0x6ff81213 }, 121 | { "NvAPI_GPU_GetCurrentPstate", 0x927da4f6 }, 122 | { "NvAPI_GPU_GetDynamicPstatesInfoEx", 0x60ded2ed }, 123 | { "NvAPI_GPU_GetThermalSettings", 0xe3640a56 }, 124 | { "NvAPI_GPU_GetAllClockFrequencies", 0xdcb616c3 }, 125 | { "NvAPI_GPU_QueryIlluminationSupport", 0xa629da31 }, 126 | { "NvAPI_GPU_GetIllumination", 0x9a1b9365 }, 127 | { "NvAPI_GPU_SetIllumination", 0x0254a187 }, 128 | { "NvAPI_GPU_ClientIllumDevicesGetInfo", 0xd4100e58 }, 129 | { "NvAPI_GPU_ClientIllumDevicesGetControl", 0x73c01d58 }, 130 | { "NvAPI_GPU_ClientIllumDevicesSetControl", 0x57024c62 }, 131 | { "NvAPI_GPU_ClientIllumZonesGetInfo", 0x4b81241b }, 132 | { "NvAPI_GPU_ClientIllumZonesGetControl", 0x3dbf5764 }, 133 | { "NvAPI_GPU_ClientIllumZonesSetControl", 0x197d065e }, 134 | { "NvAPI_Event_RegisterCallback", 0xe6dbea69 }, 135 | { "NvAPI_Event_UnregisterCallback", 0xde1f9b45 }, 136 | { "NvAPI_EnumNvidiaDisplayHandle", 0x9abdd40d }, 137 | { "NvAPI_EnumNvidiaUnAttachedDisplayHandle", 0x20de9260 }, 138 | { "NvAPI_CreateDisplayFromUnAttachedDisplay", 0x63f9799e }, 139 | { "NvAPI_GetAssociatedNvidiaDisplayHandle", 0x35c29134 }, 140 | { "NvAPI_DISP_GetAssociatedUnAttachedNvidiaDisplayHandle", 0xa70503b2 }, 141 | { "NvAPI_GetAssociatedNvidiaDisplayName", 0x22a78b05 }, 142 | { "NvAPI_GetUnAttachedAssociatedDisplayName", 0x4888d790 }, 143 | { "NvAPI_EnableHWCursor", 0x2863148d }, 144 | { "NvAPI_DisableHWCursor", 0xab163097 }, 145 | { "NvAPI_GetVBlankCounter", 0x67b5db55 }, 146 | { "NvAPI_SetRefreshRateOverride", 0x3092ac32 }, 147 | { "NvAPI_GetAssociatedDisplayOutputId", 0xd995937e }, 148 | { "NvAPI_GetDisplayPortInfo", 0xc64ff367 }, 149 | { "NvAPI_SetDisplayPort", 0xfa13e65a }, 150 | { "NvAPI_GetHDMISupportInfo", 0x6ae16ec3 }, 151 | { "NvAPI_Disp_InfoFrameControl", 0x6067af3f }, 152 | { "NvAPI_Disp_ColorControl", 0x92f9d80d }, 153 | { "NvAPI_Disp_GetHdrCapabilities", 0x84f2a8df }, 154 | { "NvAPI_Disp_HdrColorControl", 0x351da224 }, 155 | { "NvAPI_Disp_SetSourceColorSpace", 0x473b6caf }, 156 | { "NvAPI_Disp_GetSourceColorSpace", 0xceedc85b }, 157 | { "NvAPI_Disp_SetSourceHdrMetadata", 0x905eb63b }, 158 | { "NvAPI_Disp_GetSourceHdrMetadata", 0x0d3f52da }, 159 | { "NvAPI_Disp_SetOutputMode", 0x98e7661a }, 160 | { "NvAPI_Disp_GetOutputMode", 0x81fed88d }, 161 | { "NvAPI_Disp_SetHdrToneMapping", 0xdd6da362 }, 162 | { "NvAPI_Disp_GetHdrToneMapping", 0xfbd36e71 }, 163 | { "NvAPI_DISP_GetTiming", 0x175167e9 }, 164 | { "NvAPI_DISP_GetMonitorCapabilities", 0x3b05c7e1 }, 165 | { "NvAPI_DISP_GetMonitorColorCapabilities", 0x6ae4cfb5 }, 166 | { "NvAPI_DISP_EnumCustomDisplay", 0xa2072d59 }, 167 | { "NvAPI_DISP_TryCustomDisplay", 0x1f7db630 }, 168 | { "NvAPI_DISP_DeleteCustomDisplay", 0x552e5b9b }, 169 | { "NvAPI_DISP_SaveCustomDisplay", 0x49882876 }, 170 | { "NvAPI_DISP_RevertCustomDisplayTrial", 0xcbbd40f0 }, 171 | { "NvAPI_GetView", 0xd6b99d89 }, 172 | { "NvAPI_GetViewEx", 0xdbbc0af4 }, 173 | { "NvAPI_GetSupportedViews", 0x66fb7fc0 }, 174 | { "NvAPI_DISP_GetDisplayIdByDisplayName", 0xae457190 }, 175 | { "NvAPI_DISP_GetGDIPrimaryDisplayId", 0x1e9d8a31 }, 176 | { "NvAPI_DISP_GetDisplayConfig", 0x11abccf8 }, 177 | { "NvAPI_DISP_SetDisplayConfig", 0x5d8cf8de }, 178 | { "NvAPI_DISP_GetEdidData", 0x436ced76 }, 179 | { "NvAPI_DISP_GetAdaptiveSyncData", 0xb73d1ee9 }, 180 | { "NvAPI_DISP_SetAdaptiveSyncData", 0x3eebba1d }, 181 | { "NvAPI_DISP_GetVirtualRefreshRateData", 0x8c00429a }, 182 | { "NvAPI_DISP_SetVirtualRefreshRateData", 0x5abbe6a3 }, 183 | { "NvAPI_DISP_SetPreferredStereoDisplay", 0xc9d0e25f }, 184 | { "NvAPI_DISP_GetPreferredStereoDisplay", 0x1f6b4666 }, 185 | { "NvAPI_DISP_GetNvManagedDedicatedDisplays", 0xdbdf0cb2 }, 186 | { "NvAPI_DISP_AcquireDedicatedDisplay", 0x47c917ba }, 187 | { "NvAPI_DISP_ReleaseDedicatedDisplay", 0x1247825f }, 188 | { "NvAPI_Disp_GetDisplayIdInfo", 0xbae8aa5e }, 189 | { "NvAPI_Disp_GetDisplayIdsFromTarget", 0xe7e5f89e }, 190 | { "NvAPI_Disp_GetVRRInfo", 0xdf8fda57 }, 191 | { "NvAPI_Mosaic_GetSupportedTopoInfo", 0xfdb63c81 }, 192 | { "NvAPI_Mosaic_GetTopoGroup", 0xcb89381d }, 193 | { "NvAPI_Mosaic_GetOverlapLimits", 0x989685f0 }, 194 | { "NvAPI_Mosaic_SetCurrentTopo", 0x9b542831 }, 195 | { "NvAPI_Mosaic_GetCurrentTopo", 0xec32944e }, 196 | { "NvAPI_Mosaic_EnableCurrentTopo", 0x5f1aa66c }, 197 | { "NvAPI_Mosaic_GetDisplayViewportsByResolution", 0xdc6dc8d3 }, 198 | { "NvAPI_Mosaic_SetDisplayGrids", 0x4d959a89 }, 199 | { "NvAPI_Mosaic_ValidateDisplayGrids", 0xcf43903d }, 200 | { "NvAPI_Mosaic_EnumDisplayModes", 0x78db97d7 }, 201 | { "NvAPI_Mosaic_EnumDisplayGrids", 0xdf2887af }, 202 | { "NvAPI_GetSupportedMosaicTopologies", 0x410b5c25 }, 203 | { "NvAPI_GetCurrentMosaicTopology", 0xf60852bd }, 204 | { "NvAPI_SetCurrentMosaicTopology", 0xd54b8989 }, 205 | { "NvAPI_EnableCurrentMosaicTopology", 0x74073cc9 }, 206 | { "NvAPI_GSync_EnumSyncDevices", 0xd9639601 }, 207 | { "NvAPI_GSync_QueryCapabilities", 0x44a3f1d1 }, 208 | { "NvAPI_GSync_GetTopology", 0x4562bc38 }, 209 | { "NvAPI_GSync_SetSyncStateSettings", 0x60acdfdd }, 210 | { "NvAPI_GSync_GetControlParameters", 0x16de1c6a }, 211 | { "NvAPI_GSync_SetControlParameters", 0x8bbff88b }, 212 | { "NvAPI_GSync_AdjustSyncDelay", 0x2d11ff51 }, 213 | { "NvAPI_GSync_GetSyncStatus", 0xf1f5b434 }, 214 | { "NvAPI_GSync_GetStatusParameters", 0x70d404ec }, 215 | { "NvAPI_D3D_GetCurrentSLIState", 0x4b708b54 }, 216 | { "NvAPI_D3D9_RegisterResource", 0xa064bdfc }, 217 | { "NvAPI_D3D9_UnregisterResource", 0xbb2b17aa }, 218 | { "NvAPI_D3D9_AliasSurfaceAsTexture", 0xe5ceae41 }, 219 | { "NvAPI_D3D9_StretchRectEx", 0x22de03aa }, 220 | { "NvAPI_D3D9_ClearRT", 0x332d3942 }, 221 | { "NvAPI_D3D_GetObjectHandleForResource", 0xfceac864 }, 222 | { "NvAPI_D3D_SetResourceHint", 0x6c0ed98c }, 223 | { "NvAPI_D3D_BeginResourceRendering", 0x91123d6a }, 224 | { "NvAPI_D3D_EndResourceRendering", 0x37e7191c }, 225 | { "NvAPI_D3D9_GetSurfaceHandle", 0x0f2dd3f2 }, 226 | { "NvAPI_D3D9_VideoSetStereoInfo", 0xb852f4db }, 227 | { "NvAPI_D3D10_SetDepthBoundsTest", 0x4eadf5d2 }, 228 | { "NvAPI_D3D11_CreateDevice", 0x6a16d3a0 }, 229 | { "NvAPI_D3D11_CreateDeviceAndSwapChain", 0xbb939ee5 }, 230 | { "NvAPI_D3D11_SetDepthBoundsTest", 0x7aaf7a04 }, 231 | { "NvAPI_D3D11_IsNvShaderExtnOpCodeSupported", 0x5f68da40 }, 232 | { "NvAPI_D3D11_SetNvShaderExtnSlot", 0x8e90bb9f }, 233 | { "NvAPI_D3D12_SetNvShaderExtnSlotSpace", 0xac2dfeb5 }, 234 | { "NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread", 0x43d867c0 }, 235 | { "NvAPI_D3D11_SetNvShaderExtnSlotLocalThread", 0x0e6482a0 }, 236 | { "NvAPI_D3D11_BeginUAVOverlapEx", 0xba08208a }, 237 | { "NvAPI_D3D11_BeginUAVOverlap", 0x65b93ca8 }, 238 | { "NvAPI_D3D11_EndUAVOverlap", 0x2216a357 }, 239 | { "NvAPI_D3D11_GetResourceHandle", 0x09d52986 }, 240 | { "NvAPI_D3D_SetFPSIndicatorState", 0xa776e8db }, 241 | { "NvAPI_D3D9_Present", 0x05650beb }, 242 | { "NvAPI_D3D9_QueryFrameCount", 0x9083e53a }, 243 | { "NvAPI_D3D9_ResetFrameCount", 0xfa6a0675 }, 244 | { "NvAPI_D3D9_QueryMaxSwapGroup", 0x5995410d }, 245 | { "NvAPI_D3D9_QuerySwapGroup", 0xeba4d232 }, 246 | { "NvAPI_D3D9_JoinSwapGroup", 0x7d44bb54 }, 247 | { "NvAPI_D3D9_BindSwapBarrier", 0x9c39c246 }, 248 | { "NvAPI_D3D_SetVerticalSyncMode", 0x5526cfd1 }, 249 | { "NvAPI_D3D1x_Present", 0x03b845a1 }, 250 | { "NvAPI_D3D1x_QueryFrameCount", 0x9152e055 }, 251 | { "NvAPI_D3D1x_ResetFrameCount", 0xfbbb031a }, 252 | { "NvAPI_D3D1x_QueryMaxSwapGroup", 0x9bb9d68f }, 253 | { "NvAPI_D3D1x_QuerySwapGroup", 0x407f67aa }, 254 | { "NvAPI_D3D1x_JoinSwapGroup", 0x14610cd7 }, 255 | { "NvAPI_D3D1x_BindSwapBarrier", 0x9de8c729 }, 256 | { "NvAPI_D3D12_QueryPresentBarrierSupport", 0xa15faef7 }, 257 | { "NvAPI_D3D12_CreatePresentBarrierClient", 0x4d815de9 }, 258 | { "NvAPI_D3D12_RegisterPresentBarrierResources", 0xd53c9ef0 }, 259 | { "NvAPI_DestroyPresentBarrierClient", 0x3c5c351b }, 260 | { "NvAPI_JoinPresentBarrier", 0x17f6bf82 }, 261 | { "NvAPI_LeavePresentBarrier", 0xc3ec5a7f }, 262 | { "NvAPI_QueryPresentBarrierFrameStatistics", 0x61b844a1 }, 263 | { "NvAPI_D3D12_CreateDDisplayPresentBarrierClient", 0xb5a21987 }, 264 | { "NvAPI_D3D11_CreateRasterizerState", 0xdb8d28af }, 265 | { "NvAPI_D3D_ConfigureAnsel", 0x341c6c7f }, 266 | { "NvAPI_D3D11_CreateTiledTexture2DArray", 0x7886981a }, 267 | { "NvAPI_D3D11_CheckFeatureSupport", 0x106a487e }, 268 | { "NvAPI_D3D11_CreateImplicitMSAATexture2D", 0xb8f79632 }, 269 | { "NvAPI_D3D12_CreateCommittedImplicitMSAATexture2D", 0x24c6a07b }, 270 | { "NvAPI_D3D11_ResolveSubresourceRegion", 0xe6bfedd6 }, 271 | { "NvAPI_D3D12_ResolveSubresourceRegion", 0xc24a15bf }, 272 | { "NvAPI_D3D11_TiledTexture2DArrayGetDesc", 0xf1a2b9d5 }, 273 | { "NvAPI_D3D11_UpdateTileMappings", 0x9a06ea07 }, 274 | { "NvAPI_D3D11_CopyTileMappings", 0xc09ee6bc }, 275 | { "NvAPI_D3D11_TiledResourceBarrier", 0xd6839099 }, 276 | { "NvAPI_D3D11_AliasMSAATexture2DAsNonMSAA", 0xf1c54fc9 }, 277 | { "NvAPI_D3D11_CreateGeometryShaderEx_2", 0x99ed5c1c }, 278 | { "NvAPI_D3D11_CreateVertexShaderEx", 0x0beaa0b2 }, 279 | { "NvAPI_D3D11_CreateHullShaderEx", 0xb53cab00 }, 280 | { "NvAPI_D3D11_CreateDomainShaderEx", 0xa0d7180d }, 281 | { "NvAPI_D3D11_CreatePixelShaderEx_2", 0x4162822b }, 282 | { "NvAPI_D3D11_CreateFastGeometryShaderExplicit", 0x71ab7c9c }, 283 | { "NvAPI_D3D11_CreateFastGeometryShader", 0x525d43be }, 284 | { "NvAPI_D3D11_DecompressView", 0x3a94e822 }, 285 | { "NvAPI_D3D12_CreateGraphicsPipelineState", 0x2fc28856 }, 286 | { "NvAPI_D3D12_CreateComputePipelineState", 0x2762deac }, 287 | { "NvAPI_D3D12_SetDepthBoundsTestValues", 0xb9333fe9 }, 288 | { "NvAPI_D3D12_CreateReservedResource", 0x2c85f101 }, 289 | { "NvAPI_D3D12_CreateHeap", 0x5cb397cf }, 290 | { "NvAPI_D3D12_CreateHeap2", 0x924be9d6 }, 291 | { "NvAPI_D3D12_QueryCpuVisibleVidmem", 0x26322bc3 }, 292 | { "NvAPI_D3D12_ReservedResourceGetDesc", 0x9aa2aabb }, 293 | { "NvAPI_D3D12_UpdateTileMappings", 0xc6017a7d }, 294 | { "NvAPI_D3D12_CopyTileMappings", 0x47f78194 }, 295 | { "NvAPI_D3D12_ResourceAliasingBarrier", 0xb942bab7 }, 296 | { "NvAPI_D3D12_CaptureUAVInfo", 0x6e5ea9db }, 297 | { "NvAPI_D3D11_GetResourceGPUVirtualAddressEx", 0xaf6d14da }, 298 | { "NvAPI_D3D11_EnumerateMetaCommands", 0xc7453ba8 }, 299 | { "NvAPI_D3D11_CreateMetaCommand", 0xf505fba0 }, 300 | { "NvAPI_D3D11_InitializeMetaCommand", 0xaec629e9 }, 301 | { "NvAPI_D3D11_ExecuteMetaCommand", 0x82236c47 }, 302 | { "NvAPI_D3D12_EnumerateMetaCommands", 0xcd9141d8 }, 303 | { "NvAPI_D3D12_CreateMetaCommand", 0xeb29634b }, 304 | { "NvAPI_D3D12_InitializeMetaCommand", 0xa4125399 }, 305 | { "NvAPI_D3D12_ExecuteMetaCommand", 0xde24fc3d }, 306 | { "NvAPI_D3D12_CreateCommittedResource", 0x027e98ae }, 307 | { "NvAPI_D3D12_GetCopyableFootprints", 0xf6305eb5 }, 308 | { "NvAPI_D3D12_CopyTextureRegion", 0x82b91b25 }, 309 | { "NvAPI_D3D12_IsNvShaderExtnOpCodeSupported", 0x3dfacec8 }, 310 | { "NvAPI_D3D12_GetOptimalThreadCountForMesh", 0xb43995cb }, 311 | { "NvAPI_D3D_IsGSyncCapable", 0x9c1eed78 }, 312 | { "NvAPI_D3D_IsGSyncActive", 0xe942b0ff }, 313 | { "NvAPI_D3D1x_DisableShaderDiskCache", 0xd0cbca7d }, 314 | { "NvAPI_D3D11_MultiGPU_GetCaps", 0xd2d25687 }, 315 | { "NvAPI_D3D11_MultiGPU_Init", 0x017be49e }, 316 | { "NvAPI_D3D11_CreateMultiGPUDevice", 0xbdb20007 }, 317 | { "NvAPI_D3D_QuerySinglePassStereoSupport", 0x6f5f0a6d }, 318 | { "NvAPI_D3D_SetSinglePassStereoMode", 0xa39e6e6e }, 319 | { "NvAPI_D3D12_QuerySinglePassStereoSupport", 0x3b03791b }, 320 | { "NvAPI_D3D12_SetSinglePassStereoMode", 0x83556d87 }, 321 | { "NvAPI_D3D_QueryMultiViewSupport", 0xb6e0a41c }, 322 | { "NvAPI_D3D_SetMultiViewMode", 0x8285c8da }, 323 | { "NvAPI_D3D_QueryModifiedWSupport", 0xcbf9f4f5 }, 324 | { "NvAPI_D3D_SetModifiedWMode", 0x06ea4bf4 }, 325 | { "NvAPI_D3D12_QueryModifiedWSupport", 0x51235248 }, 326 | { "NvAPI_D3D12_SetModifiedWMode", 0xe1fdaba7 }, 327 | { "NvAPI_D3D_CreateLateLatchObject", 0x2db27d09 }, 328 | { "NvAPI_D3D_QueryLateLatchSupport", 0x8ceca0ec }, 329 | { "NvAPI_D3D_RegisterDevice", 0x8c02c4d0 }, 330 | { "NvAPI_D3D11_MultiDrawInstancedIndirect", 0xd4e26bbf }, 331 | { "NvAPI_D3D11_MultiDrawIndexedInstancedIndirect", 0x59e890f9 }, 332 | { "NvAPI_D3D_ImplicitSLIControl", 0x2aede111 }, 333 | { "NvAPI_D3D12_GetNeedsAppFPBlendClamping", 0x6ef4d2d1 }, 334 | { "NvAPI_D3D12_UseDriverHeapPriorities", 0xf0d978a8 }, 335 | { "NvAPI_D3D12_Mosaic_GetCompanionAllocations", 0xa46022c7 }, 336 | { "NvAPI_D3D12_Mosaic_GetViewportAndGpuPartitions", 0xb092b818 }, 337 | { "NvAPI_D3D1x_GetGraphicsCapabilities", 0x52b1499a }, 338 | { "NvAPI_D3D12_GetGraphicsCapabilities", 0x01e87354 }, 339 | { "NvAPI_D3D11_RSSetExclusiveScissorRects", 0xae4d73ef }, 340 | { "NvAPI_D3D11_RSSetViewportsPixelShadingRates", 0x34f7938f }, 341 | { "NvAPI_D3D11_CreateShadingRateResourceView", 0x99ca2dff }, 342 | { "NvAPI_D3D11_RSSetShadingRateResourceView", 0x1b0c2f83 }, 343 | { "NvAPI_D3D11_RSGetPixelShadingRateSampleOrder", 0x092442a1 }, 344 | { "NvAPI_D3D11_RSSetPixelShadingRateSampleOrder", 0xa942373a }, 345 | { "NvAPI_D3D_InitializeVRSHelper", 0x4780d70b }, 346 | { "NvAPI_D3D_InitializeNvGazeHandler", 0x5b3b7479 }, 347 | { "NvAPI_D3D_InitializeSMPAssist", 0x42763d0c }, 348 | { "NvAPI_D3D_QuerySMPAssistSupport", 0xc57921de }, 349 | { "NvAPI_D3D_GetSleepStatus", 0xaef96ca1 }, 350 | { "NvAPI_D3D_SetSleepMode", 0xac1ca9e0 }, 351 | { "NvAPI_D3D_Sleep", 0x852cd1d2 }, 352 | { "NvAPI_D3D_SetReflexSync", 0xb9f6faff }, 353 | { "NvAPI_D3D_GetLatency", 0x1a587f9c }, 354 | { "NvAPI_D3D_SetLatencyMarker", 0xd9984c05 }, 355 | { "NvAPI_D3D12_SetAsyncFrameMarker", 0x13c98f73 }, 356 | { "NvAPI_D3D12_NotifyOutOfBandCommandQueue", 0x03d6e8cb }, 357 | { "NvAPI_D3D12_CreateCubinComputeShader", 0x2a2c79e8 }, 358 | { "NvAPI_D3D12_CreateCubinComputeShaderEx", 0x3151211b }, 359 | { "NvAPI_D3D12_CreateCubinComputeShaderWithName", 0x1dc7261f }, 360 | { "NvAPI_D3D12_LaunchCubinShader", 0x5c52bb86 }, 361 | { "NvAPI_D3D12_DestroyCubinComputeShader", 0x7fb785ba }, 362 | { "NvAPI_D3D12_GetCudaTextureObject", 0x80403fc9 }, 363 | { "NvAPI_D3D12_GetCudaSurfaceObject", 0x48f5b2ee }, 364 | { "NvAPI_D3D12_IsFatbinPTXSupported", 0x70c07832 }, 365 | { "NvAPI_D3D12_CreateCuModule", 0xad1a677d }, 366 | { "NvAPI_D3D12_EnumFunctionsInModule", 0x7ab88d88 }, 367 | { "NvAPI_D3D12_CreateCuFunction", 0xe2436e22 }, 368 | { "NvAPI_D3D12_LaunchCuKernelChain", 0x24973538 }, 369 | { "NvAPI_D3D12_LaunchCuKernelChainEx", 0x846a9bf0 }, 370 | { "NvAPI_D3D12_DestroyCuModule", 0x41c65285 }, 371 | { "NvAPI_D3D12_DestroyCuFunction", 0xdf295ea6 }, 372 | { "NvAPI_D3D11_CreateCubinComputeShader", 0x0ed98181 }, 373 | { "NvAPI_D3D11_CreateCubinComputeShaderEx", 0x32c2a0f6 }, 374 | { "NvAPI_D3D11_CreateCubinComputeShaderWithName", 0xb672be19 }, 375 | { "NvAPI_D3D11_LaunchCubinShader", 0x427e236d }, 376 | { "NvAPI_D3D11_DestroyCubinComputeShader", 0x01682c86 }, 377 | { "NvAPI_D3D11_IsFatbinPTXSupported", 0x6086bd93 }, 378 | { "NvAPI_D3D11_CreateUnorderedAccessView", 0x74a497a1 }, 379 | { "NvAPI_D3D11_CreateShaderResourceView", 0x65cb431e }, 380 | { "NvAPI_D3D11_CreateSamplerState", 0x89eca416 }, 381 | { "NvAPI_D3D11_GetCudaTextureObject", 0x9006fa68 }, 382 | { "NvAPI_D3D11_GetResourceGPUVirtualAddress", 0x1819b423 }, 383 | { "NvAPI_D3D12_GetRaytracingCaps", 0x85a6c2a0 }, 384 | { "NvAPI_D3D12_EnableRaytracingValidation", 0x1de5991b }, 385 | { "NvAPI_D3D12_RegisterRaytracingValidationMessageCallback", 0x8554eb38 }, 386 | { "NvAPI_D3D12_UnregisterRaytracingValidationMessageCallback", 0x26975da6 }, 387 | { "NvAPI_D3D12_FlushRaytracingValidationMessages", 0xb8fb1fcb }, 388 | { "NvAPI_D3D12_GetRaytracingDisplacementMicromapArrayPrebuildInfo", 0xfa99b6de }, 389 | { "NvAPI_D3D12_GetRaytracingOpacityMicromapArrayPrebuildInfo", 0x4726d180 }, 390 | { "NvAPI_D3D12_SetCreatePipelineStateOptions", 0x5c607a27 }, 391 | { "NvAPI_D3D12_CheckDriverMatchingIdentifierEx", 0xafb237d4 }, 392 | { "NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx", 0x8d025b77 }, 393 | { "NvAPI_D3D12_BuildRaytracingOpacityMicromapArray", 0x814f8d11 }, 394 | { "NvAPI_D3D12_RelocateRaytracingOpacityMicromapArray", 0x0425c538 }, 395 | { "NvAPI_D3D12_BuildRaytracingDisplacementMicromapArray", 0x066f569d }, 396 | { "NvAPI_D3D12_RelocateRaytracingDisplacementMicromapArray", 0x1c142308 }, 397 | { "NvAPI_D3D12_EmitRaytracingDisplacementMicromapArrayPostbuildInfo", 0x68b9a790 }, 398 | { "NvAPI_D3D12_EmitRaytracingOpacityMicromapArrayPostbuildInfo", 0x1d9a39b6 }, 399 | { "NvAPI_D3D12_BuildRaytracingAccelerationStructureEx", 0xe24ead45 }, 400 | { "NvAPI_D3D12_QueryWorkstationFeatureProperties", 0xa92ea23a }, 401 | { "NvAPI_D3D12_CreateCommittedRDMABuffer", 0xe78dcb44 }, 402 | { "NvAPI_DirectD3D12GraphicsCommandList_Create", 0x74a4e712 }, 403 | { "NvAPI_DirectD3D12GraphicsCommandList_Release", 0x99da3dde }, 404 | { "NvAPI_DirectD3D12GraphicsCommandList_Reset", 0x999c26d8 }, 405 | { "NvAPI_VIO_GetCapabilities", 0x1dc91303 }, 406 | { "NvAPI_VIO_Open", 0x44ee4841 }, 407 | { "NvAPI_VIO_Close", 0xd01bd237 }, 408 | { "NvAPI_VIO_Status", 0x0e6ce4f1 }, 409 | { "NvAPI_VIO_SyncFormatDetect", 0x118d48a3 }, 410 | { "NvAPI_VIO_GetConfig", 0xd34a789b }, 411 | { "NvAPI_VIO_SetConfig", 0x0e4eec07 }, 412 | { "NvAPI_VIO_SetCSC", 0xa1ec8d74 }, 413 | { "NvAPI_VIO_GetCSC", 0x7b0d72a3 }, 414 | { "NvAPI_VIO_SetGamma", 0x964bf452 }, 415 | { "NvAPI_VIO_GetGamma", 0x51d53d06 }, 416 | { "NvAPI_VIO_SetSyncDelay", 0x2697a8d1 }, 417 | { "NvAPI_VIO_GetSyncDelay", 0x462214a9 }, 418 | { "NvAPI_VIO_GetPCIInfo", 0xb981d935 }, 419 | { "NvAPI_VIO_IsRunning", 0x96bd040e }, 420 | { "NvAPI_VIO_Start", 0xcde8e1a3 }, 421 | { "NvAPI_VIO_Stop", 0x6ba2a5d6 }, 422 | { "NvAPI_VIO_IsFrameLockModeCompatible", 0x7bf0a94d }, 423 | { "NvAPI_VIO_EnumDevices", 0xfd7c5557 }, 424 | { "NvAPI_VIO_QueryTopology", 0x869534e2 }, 425 | { "NvAPI_VIO_EnumSignalFormats", 0xead72fe4 }, 426 | { "NvAPI_VIO_EnumDataFormats", 0x221fa8e8 }, 427 | { "NvAPI_Stereo_CreateConfigurationProfileRegistryKey", 0xbe7692ec }, 428 | { "NvAPI_Stereo_DeleteConfigurationProfileRegistryKey", 0xf117b834 }, 429 | { "NvAPI_Stereo_SetConfigurationProfileValue", 0x24409f48 }, 430 | { "NvAPI_Stereo_DeleteConfigurationProfileValue", 0x49bceecf }, 431 | { "NvAPI_Stereo_Enable", 0x239c4545 }, 432 | { "NvAPI_Stereo_Disable", 0x2ec50c2b }, 433 | { "NvAPI_Stereo_IsEnabled", 0x348ff8e1 }, 434 | { "NvAPI_Stereo_GetStereoSupport", 0x296c434d }, 435 | { "NvAPI_Stereo_CreateHandleFromIUnknown", 0xac7e37f4 }, 436 | { "NvAPI_Stereo_DestroyHandle", 0x3a153134 }, 437 | { "NvAPI_Stereo_Activate", 0xf6a1ad68 }, 438 | { "NvAPI_Stereo_Deactivate", 0x2d68de96 }, 439 | { "NvAPI_Stereo_IsActivated", 0x1fb0bc30 }, 440 | { "NvAPI_Stereo_GetSeparation", 0x451f2134 }, 441 | { "NvAPI_Stereo_SetSeparation", 0x5c069fa3 }, 442 | { "NvAPI_Stereo_DecreaseSeparation", 0xda044458 }, 443 | { "NvAPI_Stereo_IncreaseSeparation", 0xc9a8ecec }, 444 | { "NvAPI_Stereo_GetConvergence", 0x4ab00934 }, 445 | { "NvAPI_Stereo_SetConvergence", 0x3dd6b54b }, 446 | { "NvAPI_Stereo_DecreaseConvergence", 0x4c87e317 }, 447 | { "NvAPI_Stereo_IncreaseConvergence", 0xa17daabe }, 448 | { "NvAPI_Stereo_GetFrustumAdjustMode", 0xe6839b43 }, 449 | { "NvAPI_Stereo_SetFrustumAdjustMode", 0x7be27fa2 }, 450 | { "NvAPI_Stereo_CaptureJpegImage", 0x932cb140 }, 451 | { "NvAPI_Stereo_InitActivation", 0xc7177702 }, 452 | { "NvAPI_Stereo_Trigger_Activation", 0x0d6c6cd2 }, 453 | { "NvAPI_Stereo_CapturePngImage", 0x8b7e99b5 }, 454 | { "NvAPI_Stereo_ReverseStereoBlitControl", 0x3cd58f89 }, 455 | { "NvAPI_Stereo_SetNotificationMessage", 0x6b9b409e }, 456 | { "NvAPI_Stereo_SetActiveEye", 0x96eea9f8 }, 457 | { "NvAPI_Stereo_SetDriverMode", 0x5e8f0bec }, 458 | { "NvAPI_Stereo_GetEyeSeparation", 0xce653127 }, 459 | { "NvAPI_Stereo_IsWindowedModeSupported", 0x40c8ed5e }, 460 | { "NvAPI_Stereo_SetSurfaceCreationMode", 0xf5dcfcba }, 461 | { "NvAPI_Stereo_GetSurfaceCreationMode", 0x36f1c736 }, 462 | { "NvAPI_Stereo_Debug_WasLastDrawStereoized", 0xed4416c5 }, 463 | { "NvAPI_Stereo_SetDefaultProfile", 0x44f0ecd1 }, 464 | { "NvAPI_Stereo_GetDefaultProfile", 0x624e21c2 }, 465 | { "NvAPI_D3D1x_CreateSwapChain", 0x1bc21b66 }, 466 | { "NvAPI_D3D9_CreateSwapChain", 0x1a131e09 }, 467 | { "NvAPI_DRS_CreateSession", 0x0694d52e }, 468 | { "NvAPI_DRS_DestroySession", 0xdad9cff8 }, 469 | { "NvAPI_DRS_LoadSettings", 0x375dbd6b }, 470 | { "NvAPI_DRS_SaveSettings", 0xfcbc7e14 }, 471 | { "NvAPI_DRS_LoadSettingsFromFile", 0xd3ede889 }, 472 | { "NvAPI_DRS_SaveSettingsToFile", 0x2be25df8 }, 473 | { "NvAPI_DRS_CreateProfile", 0xcc176068 }, 474 | { "NvAPI_DRS_DeleteProfile", 0x17093206 }, 475 | { "NvAPI_DRS_SetCurrentGlobalProfile", 0x1c89c5df }, 476 | { "NvAPI_DRS_GetCurrentGlobalProfile", 0x617bff9f }, 477 | { "NvAPI_DRS_GetProfileInfo", 0x61cd6fd6 }, 478 | { "NvAPI_DRS_SetProfileInfo", 0x16abd3a9 }, 479 | { "NvAPI_DRS_FindProfileByName", 0x7e4a9a0b }, 480 | { "NvAPI_DRS_EnumProfiles", 0xbc371ee0 }, 481 | { "NvAPI_DRS_GetNumProfiles", 0x1dae4fbc }, 482 | { "NvAPI_DRS_CreateApplication", 0x4347a9de }, 483 | { "NvAPI_DRS_DeleteApplicationEx", 0xc5ea85a1 }, 484 | { "NvAPI_DRS_DeleteApplication", 0x2c694bc6 }, 485 | { "NvAPI_DRS_GetApplicationInfo", 0xed1f8c69 }, 486 | { "NvAPI_DRS_EnumApplications", 0x7fa2173a }, 487 | { "NvAPI_DRS_FindApplicationByName", 0xeee566b2 }, 488 | { "NvAPI_DRS_SetSetting", 0x577dd202 }, 489 | { "NvAPI_DRS_GetSetting", 0x73bf8338 }, 490 | { "NvAPI_DRS_EnumSettings", 0xae3039da }, 491 | { "NvAPI_DRS_EnumAvailableSettingIds", 0xf020614a }, 492 | { "NvAPI_DRS_EnumAvailableSettingValues", 0x2ec39f90 }, 493 | { "NvAPI_DRS_GetSettingIdFromName", 0xcb7309cd }, 494 | { "NvAPI_DRS_GetSettingNameFromId", 0xd61cbe6e }, 495 | { "NvAPI_DRS_DeleteProfileSetting", 0xe4a26362 }, 496 | { "NvAPI_DRS_RestoreAllDefaults", 0x5927b094 }, 497 | { "NvAPI_DRS_RestoreProfileDefault", 0xfa5f6134 }, 498 | { "NvAPI_DRS_RestoreProfileDefaultSetting", 0x53f0381e }, 499 | { "NvAPI_DRS_GetBaseProfile", 0xda8466a0 }, 500 | { "NvAPI_SYS_GetChipSetInfo", 0x53dabbca }, 501 | { "NvAPI_SYS_GetLidAndDockInfo", 0xcda14d8a }, 502 | { "NvAPI_SYS_GetDisplayIdFromGpuAndOutputId", 0x08f2bab4 }, 503 | { "NvAPI_SYS_GetGpuAndOutputIdFromDisplayId", 0x112ba1a5 }, 504 | { "NvAPI_SYS_GetPhysicalGpuFromDisplayId", 0x9ea74659 }, 505 | { "NvAPI_SYS_GetDisplayDriverInfo", 0x721faceb }, 506 | { "NvAPI_GPU_ClientRegisterForUtilizationSampleUpdates", 0xadeeaf67 }, 507 | }; 508 | 509 | #endif // _NVAPI_INTERFACE_H 510 | -------------------------------------------------------------------------------- /fakenvapi.ini: -------------------------------------------------------------------------------- 1 | [fakenvapi] 2 | enable_logs=1 3 | 4 | enable_trace_logs=0 5 | 6 | ; useful in native fsg fg games 7 | force_latencyflex=0 8 | 9 | ; controls how latencyflex works 10 | ; 0 = conservative 11 | ; 1 = aggressive, will improve latency but in some cases will lower fps more than expected 12 | ; 2 = use reflex frame ids, some games are not compatible (i.e. cyberpunk) and will fallback to aggressive 13 | latencyflex_mode=0 14 | 15 | ; 0 - follow in-game setting, 1 - force disable, 2 - force enable 16 | force_reflex=0 -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('fakenvapi', 2 | 'cpp', 3 | default_options: [ 4 | 'cpp_std=c++20', 5 | 'warning_level=2' 6 | ]) 7 | 8 | cpp = meson.get_compiler('cpp') 9 | 10 | lib_dxgi = cpp.find_library('dxgi') 11 | 12 | link_args = [ 13 | '-static', 14 | '-static-libgcc', 15 | '-static-libstdc++', 16 | '-Wl,--file-alignment=4096' 17 | ] 18 | 19 | compiler_args = [ 20 | '-Wno-unused-parameter', 21 | '-D_CRT_SECURE_NO_WARNINGS', 22 | '-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR' 23 | ] 24 | 25 | spdlog_headers = include_directories('./external/spdlog/include') 26 | 27 | windows = import('windows') 28 | 29 | rc_file = configure_file( 30 | input: 'resource.rc.in', 31 | output: 'resource.rc', 32 | configuration: { 33 | 'FILEVERSION': '1,2,2,0', 34 | } 35 | ) 36 | 37 | rc = windows.compile_resources(rc_file) 38 | 39 | fakenvapi_version = vcs_tag( 40 | command: ['git', 'describe', '--always', '--tags', '--dirty=-dirty'], 41 | input: 'version.h.in', 42 | output: 'version.h' 43 | ) 44 | 45 | add_project_arguments(cpp.get_supported_arguments(compiler_args), language: 'cpp') 46 | add_project_link_arguments(cpp.get_supported_link_arguments(link_args), language: 'cpp') 47 | 48 | dxvk_cpu_family = target_machine.cpu_family() 49 | if dxvk_cpu_family == 'x86_64' 50 | target_suffix = '64' 51 | else 52 | target_suffix = '' 53 | endif 54 | 55 | subdir('src') 56 | -------------------------------------------------------------------------------- /package-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | shopt -s extglob 6 | 7 | if [ -z "$1" ] || [ -z "$2" ]; then 8 | echo "Usage: $0 version destdir" 9 | exit 1 10 | fi 11 | 12 | VERSION="$1" 13 | SRC_DIR=$(dirname "$(readlink -f "$0")") 14 | BUILD_DIR=$(realpath "$2")"/fakenvapi-$VERSION" 15 | 16 | if [ -e "$BUILD_DIR" ]; then 17 | echo "Build directory $BUILD_DIR already exists" 18 | exit 1 19 | fi 20 | 21 | shift 2 22 | 23 | crossfile="build-win" 24 | 25 | function build_arch { 26 | cd "$SRC_DIR" 27 | 28 | meson setup \ 29 | --cross-file "$SRC_DIR/$crossfile$1.txt" \ 30 | --buildtype "release" \ 31 | --prefix "$BUILD_DIR" \ 32 | --strip \ 33 | --bindir "x$1" \ 34 | --libdir "x$1" \ 35 | "$BUILD_DIR/build.$1" 36 | 37 | cd "$BUILD_DIR/build.$1" 38 | ninja install 39 | } 40 | 41 | build_arch 64 42 | build_arch 32 43 | -------------------------------------------------------------------------------- /resource.rc.in: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | VS_VERSION_INFO VERSIONINFO 4 | FILEVERSION @FILEVERSION@ 5 | PRODUCTVERSION @FILEVERSION@ 6 | FILETYPE VFT_DLL 7 | { 8 | BLOCK "StringFileInfo" 9 | { 10 | BLOCK "040904B0" 11 | { 12 | VALUE "ProductName", "fakenvapi\0" 13 | VALUE "FileVersion", "@FILEVERSION@\0" 14 | VALUE "ProductVersion", "@FILEVERSION@\0" 15 | } 16 | } 17 | BLOCK "VarFileInfo" 18 | { 19 | VALUE "Translation", 0x0409, 1252 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | 7 | enum class ForceReflex { 8 | InGame, 9 | ForceDisable, 10 | ForceEnable 11 | }; 12 | 13 | enum class LFXMode { 14 | Conservative, 15 | Aggressive, 16 | ReflexIDs 17 | }; 18 | 19 | class Config { 20 | wchar_t path[MAX_PATH]; 21 | 22 | bool _enable_logs = true; 23 | bool _enable_trace_logs = false; 24 | bool _force_latencyflex = false; 25 | LFXMode _latencyflex_mode = LFXMode::Conservative; 26 | ForceReflex _force_reflex = ForceReflex::InGame; 27 | bool _save_pcl_to_file = false; 28 | 29 | std::mutex update; 30 | 31 | static void get_ini_path(wchar_t* path) { 32 | HMODULE module = GetModuleHandle(NULL); 33 | GetModuleFileNameW(module, path, MAX_PATH); 34 | wchar_t* last_slash = wcsrchr(path, L'\\'); 35 | if (last_slash != nullptr) { 36 | *last_slash = L'\0'; 37 | } 38 | wcscat(path, L"\\fakenvapi.ini"); 39 | } 40 | 41 | int get_config(const wchar_t* section, const wchar_t* key, int default_value) { 42 | return GetPrivateProfileIntW(section, key, default_value, path); 43 | } 44 | 45 | void update_config() { 46 | update.lock(); 47 | 48 | _enable_logs = get_config(L"fakenvapi", L"enable_logs", true); 49 | _enable_trace_logs = get_config(L"fakenvapi", L"enable_trace_logs", false); 50 | _force_latencyflex = get_config(L"fakenvapi", L"force_latencyflex", false); 51 | _save_pcl_to_file = get_config(L"fakenvapi", L"save_pcl_to_file", false); 52 | 53 | auto latencyflex_mode = get_config(L"fakenvapi", L"latencyflex_mode", (int)LFXMode::Conservative); 54 | auto force_reflex = get_config(L"fakenvapi", L"force_reflex", (int)ForceReflex::InGame); 55 | 56 | if (latencyflex_mode >= (int)LFXMode::Conservative && latencyflex_mode <= (int)LFXMode::ReflexIDs) 57 | _latencyflex_mode = (LFXMode)latencyflex_mode; 58 | else 59 | _latencyflex_mode = LFXMode::Conservative; 60 | 61 | if (force_reflex >= (int)ForceReflex::InGame && force_reflex <= (int)ForceReflex::ForceEnable) 62 | _force_reflex = (ForceReflex)force_reflex; 63 | else 64 | _force_reflex = ForceReflex::InGame; 65 | 66 | auto level = _enable_trace_logs ? spdlog::level::trace : spdlog::level::info; 67 | spdlog::set_level(level); 68 | spdlog::flush_on(level); 69 | 70 | // Some of them won't be logged as logging needs to be set up 71 | spdlog::info("Config updated"); 72 | 73 | // TODO: make it a function 74 | spdlog::info("Config enable_trace_logs: {}", _enable_trace_logs ? "true" : "false"); 75 | spdlog::info("Config force_latencyflex: {}", _force_latencyflex ? "true" : "false"); 76 | spdlog::info("Config force_reflex: {}", (int)_force_reflex); 77 | spdlog::info("Config lfx_mode: {}", (int)_latencyflex_mode); 78 | spdlog::info("Config save_pcl_to_file: {}", _save_pcl_to_file ? "true" : "false"); 79 | 80 | update.unlock(); 81 | } 82 | 83 | FILETIME get_last_write_time(const wchar_t file_path[MAX_PATH]) { 84 | WIN32_FILE_ATTRIBUTE_DATA file_info; 85 | if (GetFileAttributesExW(file_path, GetFileExInfoStandard, &file_info)) { 86 | return file_info.ftLastWriteTime; 87 | } 88 | FILETIME filetime = { 0, 0 }; 89 | return filetime; 90 | } 91 | 92 | void monitor_config_file() { 93 | FILETIME last_write_time = get_last_write_time(path); 94 | 95 | wchar_t directory[MAX_PATH]; 96 | std::memcpy(directory, path, MAX_PATH); 97 | wchar_t* last_slash = wcsrchr(directory, L'\\'); 98 | if (last_slash != nullptr) { 99 | *last_slash = L'\0'; 100 | } 101 | 102 | HANDLE change_handle = FindFirstChangeNotificationW(directory, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE); 103 | 104 | if (change_handle == INVALID_HANDLE_VALUE) { 105 | spdlog::error("Unable to set up file change notification."); 106 | return; 107 | } 108 | 109 | while (true) { 110 | if (DWORD wait_status = WaitForSingleObject(change_handle, INFINITE); wait_status == WAIT_OBJECT_0) { 111 | FILETIME current_write_time = get_last_write_time(path); 112 | if (CompareFileTime(&last_write_time, ¤t_write_time) != 0) { 113 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); 114 | update_config(); 115 | last_write_time = current_write_time; 116 | } 117 | 118 | if (FindNextChangeNotification(change_handle) == FALSE) { 119 | spdlog::error("Unable to reset file change notification."); 120 | break; 121 | } 122 | } 123 | } 124 | 125 | FindCloseChangeNotification(change_handle); 126 | } 127 | 128 | public: 129 | static Config& get() { 130 | static Config instance; 131 | return instance; 132 | } 133 | 134 | void init_config() { 135 | get_ini_path(path); 136 | update_config(); 137 | std::thread config_monitor_thread(&Config::monitor_config_file, this); 138 | config_monitor_thread.detach(); 139 | } 140 | 141 | bool get_enable_logs () { 142 | return _enable_logs; 143 | } 144 | 145 | bool get_enable_trace_logs () { 146 | return _enable_trace_logs; 147 | } 148 | 149 | bool get_force_latencyflex () { 150 | return _force_latencyflex; 151 | } 152 | 153 | LFXMode get_latencyflex_mode() { 154 | return _latencyflex_mode; 155 | } 156 | 157 | ForceReflex get_force_reflex() { 158 | return _force_reflex; 159 | } 160 | 161 | bool get_save_pcl_to_file() { 162 | return _save_pcl_to_file; 163 | } 164 | }; 165 | -------------------------------------------------------------------------------- /src/fakenvapi.cpp: -------------------------------------------------------------------------------- 1 | #include "fakenvapi.h" 2 | 3 | namespace nvd { 4 | bool Init() { 5 | if (!device_id) { 6 | IDXGIFactory1* factory = nullptr; 7 | if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory))) { 8 | spdlog::error("Failed to create DXGI Factory"); 9 | return false; 10 | } 11 | 12 | IDXGIAdapter1* adapter = nullptr; 13 | if (FAILED(factory->EnumAdapters1(0, &adapter))) { 14 | spdlog::error("Failed to enumerate adapters"); 15 | factory->Release(); 16 | return false; 17 | } 18 | 19 | DXGI_ADAPTER_DESC1 adapter_desc; 20 | if (FAILED(adapter->GetDesc1(&adapter_desc))) { 21 | spdlog::error("Failed to get adapter description"); 22 | adapter->Release(); 23 | factory->Release(); 24 | return false; 25 | } 26 | 27 | luid = adapter_desc.AdapterLuid; 28 | device_id = adapter_desc.DeviceId; 29 | vendor_id = adapter_desc.VendorId; 30 | subsystem_id = adapter_desc.SubSysId; 31 | revision_id = adapter_desc.Revision; 32 | 33 | adapter->Release(); 34 | factory->Release(); 35 | 36 | lowlatency_ctx.init_lfx(); 37 | } 38 | 39 | return true; 40 | } 41 | 42 | NvAPI_Status __cdecl NvAPI_Initialize() { 43 | ref_count++; 44 | 45 | if (!Init()) 46 | return ERROR(); 47 | 48 | return OK(); 49 | } 50 | 51 | NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc) { 52 | tonvss(desc, "fakenvapi"); 53 | return OK(); 54 | } 55 | 56 | NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count) { 57 | handles[0] = nullptr; 58 | *count = 1; 59 | return OK(); 60 | } 61 | 62 | NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count) { 63 | handles[0] = nullptr; 64 | *count = 1; 65 | return OK(); 66 | } 67 | 68 | NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle) { 69 | if (displayId == 0) { 70 | return OK(); 71 | } 72 | return ERROR_VALUE(NVAPI_END_ENUMERATION); 73 | } 74 | 75 | NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { 76 | *logicalHandle = nullptr; 77 | return OK(); 78 | } 79 | 80 | 81 | NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId) { 82 | *pGpuId = 42; 83 | return OK(); 84 | } 85 | 86 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU) { 87 | *pPhysicalGPU = nullptr; 88 | return OK(); 89 | } 90 | 91 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32* pGpuCount) { 92 | nvGPUHandle[0] = nullptr; 93 | *pGpuCount = 1; 94 | 95 | return OK(); 96 | } 97 | 98 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromLogicalGPU(NvLogicalGpuHandle hLogicalGPU, NvPhysicalGpuHandle hPhysicalGPU[NVAPI_MAX_PHYSICAL_GPUS], NvU32 *pGpuCount) { 99 | hPhysicalGPU[0] = nullptr; 100 | *pGpuCount = 1; 101 | 102 | return OK(); 103 | } 104 | 105 | NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { 106 | std::string error = from_error_nr(status); 107 | spdlog::error("NvAPI_GetErrorMessage gave this error: {}", error); 108 | tonvss(szMsg, error); 109 | return OK(); 110 | } 111 | 112 | NvAPI_Status __cdecl NvAPI_GetDisplayDriverVersion(NvDisplayHandle hNvDisplay, NV_DISPLAY_DRIVER_VERSION *pVersion) { 113 | if (!pVersion) 114 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 115 | 116 | pVersion->drvVersion = 99999; 117 | tonvss(pVersion->szBuildBranchString, "buildBranch"); 118 | tonvss(pVersion->szAdapterString, "NVIDIA GeForce RTX 4090"); 119 | } 120 | 121 | NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo) { 122 | auto compute_topoV1 = reinterpret_cast(pComputeTopo); 123 | compute_topoV1->gpuCount = 1; 124 | compute_topoV1->computeGpus[0].hPhysicalGpu = nullptr; 125 | compute_topoV1->computeGpus[0].flags = NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_CAPABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_ENABLE | NV_COMPUTE_GPU_TOPOLOGY_PHYSICS_RECOMMENDED; 126 | return OK(); 127 | } 128 | 129 | NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags) { 130 | *displayCount = 0; // no displays connected, may cause issues 131 | // NVAPI_NVIDIA_DISPLAY_NOT_FOUND could be considered 132 | return OK(); 133 | } 134 | 135 | NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { 136 | archInfo->architecture = NV_GPU_ARCHITECTURE_AD100; 137 | archInfo->architecture_id = NV_GPU_ARCHITECTURE_AD100; 138 | archInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_AD102; 139 | archInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_AD102; 140 | archInfo->revision = NV_GPU_CHIP_REV_UNKNOWN; 141 | archInfo->revision_id = NV_GPU_CHIP_REV_UNKNOWN; 142 | 143 | return OK(); 144 | } 145 | 146 | NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData) { 147 | if (!Init()) 148 | return ERROR(); 149 | 150 | memcpy(logicalGpuData->pOSAdapterId, &luid, sizeof(luid)); 151 | logicalGpuData->physicalGpuHandles[0] = nullptr; 152 | logicalGpuData->physicalGpuCount = 1; 153 | return OK(); 154 | } 155 | 156 | NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId) { 157 | if (!Init()) 158 | return ERROR(); 159 | 160 | *pDeviceId = (device_id << 16) | vendor_id; 161 | *pSubSystemId = subsystem_id; 162 | *pRevisionId = revision_id; 163 | *pExtDeviceId = device_id; 164 | return OK(); 165 | } 166 | 167 | NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { 168 | tonvss(szName, "NVIDIA GeForce RTX 4090"); 169 | return OK(); 170 | } 171 | 172 | NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount) { 173 | *pCount = 1; 174 | return OK(); 175 | } 176 | 177 | NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs) { 178 | if (pClkFreqs == nullptr) 179 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 180 | 181 | 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) 182 | return ERROR_VALUE(NVAPI_INCOMPATIBLE_STRUCT_VERSION); 183 | 184 | if (pClkFreqs->ClockType != static_cast(NV_GPU_CLOCK_FREQUENCIES_CURRENT_FREQ)) { 185 | return ERROR_VALUE(NVAPI_NOT_SUPPORTED); 186 | } 187 | 188 | // Reset all clock data for all domains 189 | for (auto& domain : pClkFreqs->domain) { 190 | domain.bIsPresent = 0; 191 | domain.frequency = 0; 192 | } 193 | 194 | unsigned int clock = 1600; 195 | 196 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].bIsPresent = 1; 197 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS].frequency = (clock * 1000); 198 | 199 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].bIsPresent = 1; 200 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_MEMORY].frequency = (clock * 1000); 201 | 202 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].bIsPresent = 1; 203 | pClkFreqs->domain[NVAPI_GPU_PUBLIC_CLOCK_VIDEO].frequency = (clock * 1000); 204 | return OK(); 205 | } 206 | 207 | NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId) { 208 | if (!Init()) 209 | return ERROR(); 210 | 211 | memcpy(pOSAdapterId, &luid, sizeof(luid)); 212 | return OK(); 213 | } 214 | 215 | NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo) { 216 | if (!pPstatesInfo) 217 | return ERROR(); 218 | 219 | // Initialize the structure with mock data 220 | pPstatesInfo->version = NV_GPU_PERF_PSTATES20_INFO_VER; 221 | pPstatesInfo->numPstates = 2; // Example: 2 P-states 222 | pPstatesInfo->numClocks = 3; 223 | pPstatesInfo->numBaseVoltages = 1; 224 | pPstatesInfo->ov.numVoltages = 0; 225 | 226 | // Fill mock data for P-state 0 227 | pPstatesInfo->pstates[0].pstateId = NVAPI_GPU_PERF_PSTATE_P0; 228 | pPstatesInfo->pstates[0].bIsEditable = false; 229 | pPstatesInfo->pstates[0].clocks[0].domainId = NVAPI_GPU_PUBLIC_CLOCK_GRAPHICS; 230 | pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.value = 1000; // 1 MHz 231 | pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.min = 800; 232 | pPstatesInfo->pstates[0].clocks[0].freqDelta_kHz.valueRange.max = 1200; 233 | pPstatesInfo->pstates[0].clocks[1].domainId = NVAPI_GPU_PUBLIC_CLOCK_MEMORY; 234 | pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.value = 1000; // 1 MHz 235 | pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.min = 800; 236 | pPstatesInfo->pstates[0].clocks[1].freqDelta_kHz.valueRange.max = 1200; 237 | pPstatesInfo->pstates[0].clocks[2].domainId = NVAPI_GPU_PUBLIC_CLOCK_VIDEO; 238 | pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.value = 1000; // 1 MHz 239 | pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.min = 800; 240 | pPstatesInfo->pstates[0].clocks[2].freqDelta_kHz.valueRange.max = 1200; 241 | pPstatesInfo->pstates[0].baseVoltages[0].volt_uV = 1000000; // 1V 242 | pPstatesInfo->pstates[0].baseVoltages[0].bIsEditable = false; 243 | pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.value = 1000; 244 | pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.min = 0; 245 | pPstatesInfo->pstates[0].baseVoltages[0].voltDelta_uV.valueRange.max = 0; 246 | 247 | // Fill mock data for P-state 1 248 | memcpy(&pPstatesInfo->pstates[1], &pPstatesInfo->pstates[0], sizeof(pPstatesInfo->pstates[0])); 249 | pPstatesInfo->pstates[1].pstateId = NVAPI_GPU_PERF_PSTATE_P1; 250 | 251 | return OK(); 252 | } 253 | 254 | NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId) { 255 | *displayId = 0; 256 | return OK(); 257 | } 258 | 259 | NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId) { 260 | *displayId = 0; 261 | return OK(); 262 | } 263 | 264 | NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { 265 | *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR 266 | return OK(); 267 | } 268 | 269 | NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode) { 270 | *pDisplayMode = NV_DISPLAY_OUTPUT_MODE_SDR; // meaning no HDR 271 | return OK(); 272 | } 273 | 274 | NvAPI_Status __cdecl NvAPI_Disp_GetHdrCapabilities(NvU32 displayId, NV_HDR_CAPABILITIES *pHdrCapabilities) { 275 | return OK(); 276 | } 277 | 278 | NvAPI_Status __cdecl NvAPI_Disp_HdrColorControl(NvU32 displayId, NV_HDR_COLOR_DATA *pHdrColorData) { 279 | return OK(); 280 | } 281 | 282 | NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected) { 283 | for (int i = 0; i < NV_MOSAIC_MAX_DISPLAYS; i++) { 284 | viewports[i].top = 0; 285 | viewports[i].left = 0; 286 | viewports[i].right = 0; 287 | viewports[i].bottom = 0; 288 | } 289 | return OK(); 290 | } 291 | 292 | NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { 293 | driverInfo->driverVersion = 99999; 294 | tonvss(driverInfo->szBuildBranch, "buildBranch"); 295 | driverInfo->bIsDCHDriver = 1; 296 | driverInfo->bIsNVIDIAStudioPackage = 1; 297 | driverInfo->bIsNVIDIARTXProductionBranchPackage = 1; 298 | driverInfo->bIsNVIDIARTXNewFeatureBranchPackage = 1; 299 | if (driverInfo->version == 2) 300 | tonvss(driverInfo->szBuildBaseBranch, "buildBaseBranch"); 301 | return OK(); 302 | } 303 | 304 | NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { 305 | *pDriverVersion = 99999; 306 | tonvss(szBuildBranchString, "buildBranch"); 307 | return OK(); 308 | } 309 | 310 | NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId) { 311 | *displayId = 0; 312 | return OK(); 313 | } 314 | 315 | NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId) { 316 | *hPhysicalGpu = nullptr; 317 | *outputId = 0; 318 | return OK(); 319 | } 320 | 321 | NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle) { 322 | *pHandle = (NVDX_ObjectHandle)pResource; 323 | return OK(); 324 | } 325 | 326 | NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint() { 327 | return ERROR_VALUE(NVAPI_NO_IMPLEMENTATION); 328 | } 329 | 330 | NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { 331 | pGetSleepStatusParams->bLowLatencyMode = lowlatency_ctx.active; 332 | pGetSleepStatusParams->bFsVrr = true; 333 | pGetSleepStatusParams->bCplVsyncOn = true; 334 | return OK(); 335 | } 336 | 337 | NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) { 338 | if (!Init()) 339 | return ERROR(); 340 | 341 | if (pGetLatencyParams == nullptr) 342 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 343 | 344 | memcpy(&pGetLatencyParams->frameReport, &lowlatency_ctx.frame_reports, sizeof(lowlatency_ctx.frame_reports)); 345 | 346 | // FrameReport* frame_reports = reinterpret_cast(pGetLatencyParams->frameReport); 347 | // std::sort(frame_reports, frame_reports + 64, [](const FrameReport &a, const FrameReport &b) { 348 | // return a.frameID < b.frameID; 349 | // }); 350 | 351 | return OK(); 352 | } 353 | 354 | NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { 355 | if (!Init()) 356 | return ERROR(); 357 | 358 | static bool previous_boost = false; 359 | if (lowlatency_ctx.active != pSetSleepModeParams->bLowLatencyMode || previous_boost != pSetSleepModeParams->bLowLatencyBoost) { 360 | spdlog::info( 361 | "Changed reflex settings to: {}, boost: {}", 362 | pSetSleepModeParams->bLowLatencyMode ? "enabled" : "disabled", 363 | pSetSleepModeParams->bLowLatencyBoost ? "enabled" : "disabled" 364 | ); 365 | lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; 366 | previous_boost = pSetSleepModeParams->bLowLatencyBoost; 367 | } 368 | lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); 369 | return OK(); 370 | } 371 | 372 | NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { 373 | if (!Init()) 374 | return ERROR(); 375 | 376 | if (!pDev) 377 | return ERROR(); 378 | 379 | lowlatency_ctx.init_al2(pDev); 380 | 381 | lowlatency_ctx.report_marker(pSetLatencyMarkerParams); 382 | 383 | static std::thread::id simulation_start_thread = {}; 384 | 385 | switch (pSetLatencyMarkerParams->markerType) { 386 | case SIMULATION_START: 387 | log_event("marker_SIMULATION_START", "{}", pSetLatencyMarkerParams->frameID); 388 | lowlatency_ctx.pcl_start(pSetLatencyMarkerParams->frameID); 389 | simulation_start_thread = std::this_thread::get_id(); 390 | if (lowlatency_ctx.call_spot == CallSpot::SleepCall) { 391 | lowlatency_ctx.calls_without_sleep++; 392 | if (lowlatency_ctx.calls_without_sleep > 10) 393 | lowlatency_ctx.call_spot = CallSpot::SimulationStart; 394 | } 395 | if (lowlatency_ctx.call_spot != CallSpot::SimulationStart) break; 396 | spdlog::debug("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update(pSetLatencyMarkerParams->frameID)); 397 | break; 398 | case SIMULATION_END: 399 | log_event("marker_SIMULATION_END", "{}", pSetLatencyMarkerParams->frameID); 400 | break; 401 | case RENDERSUBMIT_START: 402 | log_event("marker_RENDERSUBMIT_START", "{}", pSetLatencyMarkerParams->frameID); 403 | break; 404 | case RENDERSUBMIT_END: 405 | log_event("marker_RENDERSUBMIT_END", "{}", pSetLatencyMarkerParams->frameID); 406 | 407 | if (!lowlatency_ctx.fg) 408 | lowlatency_ctx.pcl_end(pSetLatencyMarkerParams->frameID); 409 | 410 | if (lowlatency_ctx.get_mode() == Mode::LatencyFlex && lowlatency_ctx.lfx_mode != LFXMode::Conservative) { 411 | if (std::this_thread::get_id() == simulation_start_thread) { 412 | static bool logged = false; 413 | if (!logged) 414 | spdlog::info("Falling back to LFX Aggressive"); 415 | logged = true; 416 | lowlatency_ctx.lfx_mode = LFXMode::Aggressive; 417 | } else { 418 | lowlatency_ctx.lfx_end_frame(pSetLatencyMarkerParams->frameID); 419 | } 420 | } 421 | break; 422 | case PRESENT_START: 423 | log_event("marker_PRESENT_START", "{}", pSetLatencyMarkerParams->frameID); 424 | lowlatency_ctx.mark_end_of_rendering(pSetLatencyMarkerParams->frameID); 425 | break; 426 | case PRESENT_END: 427 | log_event("marker_PRESENT_END", "{}", pSetLatencyMarkerParams->frameID); 428 | break; 429 | case INPUT_SAMPLE: 430 | log_event("marker_INPUT_SAMPLE", "{}", pSetLatencyMarkerParams->frameID); 431 | if (lowlatency_ctx.call_spot == CallSpot::SleepCall) break; 432 | lowlatency_ctx.call_spot = CallSpot::InputSample; 433 | spdlog::debug("LowLatency update called on input sample with result: {}", lowlatency_ctx.update(pSetLatencyMarkerParams->frameID)); 434 | break; 435 | default: 436 | log_event("marker_other", "{}", pSetLatencyMarkerParams->frameID); 437 | break; 438 | } 439 | return OK(); 440 | } 441 | 442 | NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { 443 | if (!Init()) 444 | return ERROR(); 445 | 446 | if (!pDevice) 447 | return ERROR(); 448 | 449 | if (lowlatency_ctx.get_mode() == Mode::LatencyFlex && lowlatency_ctx.lfx_mode == LFXMode::ReflexIDs) 450 | return OK(); 451 | 452 | lowlatency_ctx.init_al2(pDevice); 453 | lowlatency_ctx.call_spot = CallSpot::SleepCall; 454 | lowlatency_ctx.calls_without_sleep = 0; 455 | spdlog::debug("LowLatency update called on sleep with result: {}", lowlatency_ctx.update(0)); 456 | return OK(); 457 | } 458 | 459 | NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { 460 | return OK(); 461 | } 462 | 463 | NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { 464 | *pSupported = true; 465 | return OK(); 466 | } 467 | 468 | NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext) { 469 | static bool logged = false; 470 | if (!logged) { 471 | logged = true; 472 | return OK(); 473 | } 474 | else return NVAPI_OK; //return without logging 475 | } 476 | 477 | NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext) { 478 | static bool logged = false; 479 | if (!logged) { 480 | logged = true; 481 | return OK(); 482 | } 483 | else return NVAPI_OK; //return without logging 484 | } 485 | 486 | NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext) { 487 | static bool logged = false; 488 | if (!logged) { 489 | logged = true; 490 | return OK(); 491 | } 492 | else return NVAPI_OK; //return without logging 493 | } 494 | 495 | NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize) { 496 | if (pData == nullptr) 497 | return ERROR_VALUE(NVAPI_INVALID_POINTER); 498 | 499 | switch (type) { 500 | case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_THREAD_REORDERING: 501 | if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS)) 502 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 503 | 504 | // let's hope that NvAPI_D3D12_IsNvShaderExtnOpCodeSupported returning false is enough to discourage games from attempting to use Shader Execution Reordering 505 | *(NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAPS*)pData = NVAPI_D3D12_RAYTRACING_THREAD_REORDERING_CAP_NONE; 506 | break; 507 | 508 | case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_OPACITY_MICROMAP: 509 | if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS)) 510 | return ERROR_VALUE(NVAPI_INVALID_POINTER); 511 | 512 | *(NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_OPACITY_MICROMAP_CAP_NONE; 513 | break; 514 | 515 | case NVAPI_D3D12_RAYTRACING_CAPS_TYPE_DISPLACEMENT_MICROMAP: 516 | if (dataSize != sizeof(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS)) 517 | return ERROR_VALUE(NVAPI_INVALID_POINTER); 518 | 519 | *(NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAPS*)pData = NVAPI_D3D12_RAYTRACING_DISPLACEMENT_MICROMAP_CAP_NONE; 520 | break; 521 | 522 | default: 523 | return ERROR_VALUE(NVAPI_INVALID_POINTER); 524 | } 525 | 526 | return OK(); 527 | } 528 | 529 | NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported) { 530 | // VKD3D-Proton does not know any NVIDIA intrinsics 531 | *pSupported = false; 532 | return OK(); 533 | } 534 | 535 | NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread() { 536 | return OK(); 537 | } 538 | 539 | // Taken directly from dxvk-nvapi 540 | static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { 541 | d3dDesc->Type = nvDesc->type; 542 | // 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 543 | d3dDesc->Flags = static_cast(nvDesc->flags & 0x3f); 544 | d3dDesc->NumDescs = nvDesc->numDescs; 545 | d3dDesc->DescsLayout = nvDesc->descsLayout; 546 | 547 | if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { 548 | d3dDesc->InstanceDescs = nvDesc->instanceDescs; 549 | return true; 550 | } 551 | 552 | if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS) { 553 | d3dDesc->ppGeometryDescs = reinterpret_cast(nvDesc->ppGeometryDescs); 554 | return true; 555 | } 556 | 557 | if (d3dDesc->Type == D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL && d3dDesc->DescsLayout == D3D12_ELEMENTS_LAYOUT_ARRAY) { 558 | geometryDescs.resize(d3dDesc->NumDescs); 559 | 560 | for (unsigned i = 0; i < d3dDesc->NumDescs; ++i) { 561 | auto& d3dGeoDesc = geometryDescs[i]; 562 | auto& nvGeoDesc = *reinterpret_cast(reinterpret_cast(nvDesc->pGeometryDescs) + (i * nvDesc->geometryDescStrideInBytes)); 563 | 564 | d3dGeoDesc.Flags = nvGeoDesc.flags; 565 | 566 | switch (nvGeoDesc.type) { 567 | case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES_EX: 568 | d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; 569 | d3dGeoDesc.Triangles = nvGeoDesc.triangles; 570 | break; 571 | case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS_EX: 572 | d3dGeoDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; 573 | d3dGeoDesc.AABBs = nvGeoDesc.aabbs; 574 | break; 575 | case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this 576 | spdlog::error("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); 577 | return false; 578 | case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this 579 | spdlog::error("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); 580 | return false; 581 | default: 582 | spdlog::error("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); 583 | return false; 584 | } 585 | } 586 | 587 | d3dDesc->pGeometryDescs = geometryDescs.data(); 588 | return true; 589 | } 590 | 591 | return false; 592 | } 593 | 594 | NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams) { 595 | std::vector geometryDescs{}; 596 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS desc{}; 597 | 598 | if (!ConvertBuildRaytracingAccelerationStructureInputs(pParams->pDesc, geometryDescs, &desc)) 599 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 600 | 601 | pDevice->GetRaytracingAccelerationStructurePrebuildInfo(&desc, pParams->pInfo); 602 | return OK(); 603 | } 604 | 605 | NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams) { 606 | std::vector geometryDescs{}; 607 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC desc = { 608 | .DestAccelerationStructureData = pParams->pDesc->destAccelerationStructureData, 609 | .Inputs = {}, 610 | .SourceAccelerationStructureData = pParams->pDesc->sourceAccelerationStructureData, 611 | .ScratchAccelerationStructureData = pParams->pDesc->scratchAccelerationStructureData, 612 | }; 613 | 614 | if (!ConvertBuildRaytracingAccelerationStructureInputs(&pParams->pDesc->inputs, geometryDescs, &desc.Inputs)) 615 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 616 | 617 | pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); 618 | static bool logged = false; 619 | if (!logged) { 620 | logged = true; 621 | return OK(); 622 | } 623 | else return NVAPI_OK; //return without logging 624 | } 625 | 626 | NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { 627 | return OK(); 628 | } 629 | 630 | NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { 631 | static NvU64 previous_frame_id = 0; 632 | static NvU64 current_frame_id = 0; 633 | switch (pSetAsyncFrameMarkerParams->markerType) { 634 | case PRESENT_START: 635 | log_event("async_marker_PRESENT_START", "{}", pSetAsyncFrameMarkerParams->frameID); 636 | break; 637 | case PRESENT_END: 638 | log_event("async_marker_PRESENT_END", "{}", pSetAsyncFrameMarkerParams->frameID); 639 | break; 640 | case OUT_OF_BAND_RENDERSUBMIT_START: 641 | log_event("async_marker_OUB_RENDERSUBMIT_START", "{}", pSetAsyncFrameMarkerParams->frameID); 642 | break; 643 | case OUT_OF_BAND_RENDERSUBMIT_END: 644 | log_event("async_marker_OUB_RENDERSUBMIT_END", "{}", pSetAsyncFrameMarkerParams->frameID); 645 | break; 646 | case OUT_OF_BAND_PRESENT_START: { 647 | log_event("async_marker_OUB_PRESENT_START", "{}", pSetAsyncFrameMarkerParams->frameID); 648 | constexpr size_t history_size = 12; 649 | static size_t counter = 0; 650 | static NvU64 previous_frame_ids[history_size] = {}; 651 | current_frame_id = pSetAsyncFrameMarkerParams->frameID; 652 | 653 | previous_frame_ids[counter%history_size] = current_frame_id; 654 | counter++; 655 | 656 | int repeat_count = 0; 657 | 658 | for (size_t i = 1; i < history_size; i++) { 659 | // won't catch repeat frame ids across array wrap around 660 | if (previous_frame_ids[i] == previous_frame_ids[i - 1]) { 661 | repeat_count++; 662 | } 663 | } 664 | 665 | if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; 666 | else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2 - 1) lowlatency_ctx.fg = true; 667 | 668 | lowlatency_ctx.set_fg_type(previous_frame_id != current_frame_id, current_frame_id); 669 | previous_frame_id = current_frame_id; 670 | break; 671 | } 672 | case OUT_OF_BAND_PRESENT_END: 673 | log_event("async_marker_OUB_PRESENT_END", "{}", pSetAsyncFrameMarkerParams->frameID); 674 | if (previous_frame_id == current_frame_id) 675 | lowlatency_ctx.pcl_end(pSetAsyncFrameMarkerParams->frameID); 676 | break; 677 | default: 678 | log_event("async_marker_other", "{}", pSetAsyncFrameMarkerParams->frameID); 679 | break; 680 | } 681 | return OK(); 682 | } 683 | 684 | NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session) { 685 | *session = drs_session; 686 | return OK(); 687 | } 688 | 689 | NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session) { 690 | return OK(); 691 | } 692 | 693 | NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session) { 694 | return OK(); 695 | } 696 | 697 | NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { 698 | *profile = drs_profile; 699 | return OK(); 700 | } 701 | 702 | NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { 703 | spdlog::debug("Missing get setting: {}", settingId); 704 | return OK(); 705 | } 706 | 707 | NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { 708 | spdlog::debug("Missing set setting: {}", pSetting->settingId); 709 | return OK(); 710 | } 711 | 712 | NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { 713 | return OK(); 714 | } 715 | 716 | NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { 717 | std::fill(pMiscUnk, pMiscUnk + 4, 0x1); 718 | return OK(); 719 | } 720 | 721 | NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown) { 722 | return OK(); 723 | } 724 | 725 | NvAPI_Status __cdecl NvAPI_SK_1(IUnknown* unknown) { 726 | return OK(); 727 | } 728 | 729 | NvAPI_Status __cdecl NvAPI_SK_2(IUnknown* unknown) { 730 | return OK(); 731 | } 732 | 733 | NvAPI_Status __cdecl NvAPI_SK_3(IUnknown* unknown) { 734 | return OK(); 735 | } 736 | 737 | NvAPI_Status __cdecl NvAPI_SK_4(IUnknown* unknown) { 738 | return OK(); 739 | } 740 | 741 | NvAPI_Status __cdecl NvAPI_SK_5(IUnknown* unknown) { 742 | return OK(); 743 | } 744 | 745 | NvAPI_Status __cdecl NvAPI_Unload() { 746 | if(ref_count.load() > 0) 747 | ref_count--; 748 | 749 | if(ref_count.load() == 0) 750 | lowlatency_ctx.unload(); 751 | 752 | return OK(); 753 | } 754 | 755 | NvAPI_Status __cdecl Fake_GetLatency(uint64_t* call_spot, uint64_t* target, uint64_t* latency, uint64_t* frame_time) { 756 | if (!call_spot || !target || !latency || !frame_time) return ERROR_VALUE(NVAPI_INVALID_POINTER); 757 | 758 | if (lowlatency_ctx.get_mode() != Mode::LatencyFlex) return ERROR_VALUE(NVAPI_DATA_NOT_FOUND); 759 | *call_spot = (uint64_t)lowlatency_ctx.call_spot; 760 | 761 | *target = lowlatency_ctx.lfx_stats.target; 762 | *latency = lowlatency_ctx.lfx_stats.latency; 763 | *frame_time = lowlatency_ctx.lfx_stats.frame_time; 764 | 765 | return OK(); 766 | } 767 | 768 | NvAPI_Status __cdecl Fake_InformFGState(bool fg_state) { 769 | lowlatency_ctx.forced_fg = fg_state; 770 | return OK(); 771 | } 772 | 773 | NvAPI_Status __cdecl Fake_InformPresentFG(bool frame_interpolated, uint64_t reflex_frame_id) { 774 | lowlatency_ctx.set_fg_type(frame_interpolated, reflex_frame_id); 775 | return OK(); 776 | } 777 | 778 | #if _WIN64 779 | NvAPI_Status __cdecl Fake_GetAntiLagCtx(AMD::AntiLag2DX12::Context** al2_context) { 780 | if (al2_context == nullptr) 781 | return ERROR_VALUE(NVAPI_INVALID_ARGUMENT); 782 | 783 | if (lowlatency_ctx.al2_dx12_ctx.m_pAntiLagAPI != nullptr) { 784 | *al2_context = &lowlatency_ctx.al2_dx12_ctx; 785 | return OK(); 786 | } 787 | 788 | return ERROR(); 789 | } 790 | #endif 791 | } -------------------------------------------------------------------------------- /src/fakenvapi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #if _MSC_VER 5 | #include 6 | #else 7 | #include "../external/d3d12.h" 8 | #endif 9 | #include 10 | 11 | #include "lowlatency.h" 12 | 13 | #include "util.h" 14 | #include "log.h" 15 | 16 | namespace nvd { 17 | static auto drs = 1U; 18 | static auto drs_session = reinterpret_cast(&drs); 19 | static auto drs_profile = reinterpret_cast(&drs); 20 | 21 | static LUID luid = {}; 22 | static UINT device_id = {}; 23 | static UINT vendor_id = {}; 24 | static UINT subsystem_id = {}; 25 | static UINT revision_id = {}; 26 | 27 | static std::atomic_uint ref_count = 0; 28 | 29 | static LowLatency lowlatency_ctx; 30 | 31 | NvAPI_Status __cdecl NvAPI_Initialize(); 32 | NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc); 33 | NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count); 34 | NvAPI_Status __cdecl NvAPI_EnumLogicalGPUs(NvLogicalGpuHandle handles[NVAPI_MAX_LOGICAL_GPUS], NvU32* count); 35 | NvAPI_Status __cdecl NvAPI_EnumNvidiaDisplayHandle(NvU32 displayId, NvDisplayHandle* handle); 36 | NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle); 37 | NvAPI_Status __cdecl NvAPI_GetGPUIDfromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pGpuId); 38 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUFromGPUID(NvU32 gpuId, NvPhysicalGpuHandle* pPhysicalGPU); 39 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromDisplay(NvDisplayHandle hNvDisp, NvPhysicalGpuHandle nvGPUHandle[NVAPI_MAX_PHYSICAL_GPUS], NvU32 *pGpuCount); 40 | NvAPI_Status __cdecl NvAPI_GetPhysicalGPUsFromLogicalGPU(NvLogicalGpuHandle hLogicalGPU, NvPhysicalGpuHandle hPhysicalGPU[NVAPI_MAX_PHYSICAL_GPUS], NvU32 *pGpuCount); 41 | NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg); 42 | NvAPI_Status __cdecl NvAPI_GetDisplayDriverVersion(NvDisplayHandle hNvDisplay, NV_DISPLAY_DRIVER_VERSION *pVersion); 43 | NvAPI_Status __cdecl NvAPI_GPU_CudaEnumComputeCapableGpus(NV_COMPUTE_GPU_TOPOLOGY* pComputeTopo); 44 | NvAPI_Status __cdecl NvAPI_GPU_GetConnectedDisplayIds(NvPhysicalGpuHandle handle, NV_GPU_DISPLAYIDS* displayIds, NvU32* displayCount, NvU32 flags); 45 | NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo); 46 | NvAPI_Status __cdecl NvAPI_GPU_GetLogicalGpuInfo(NvLogicalGpuHandle logicalHandle, NV_LOGICAL_GPU_DATA* logicalGpuData); 47 | NvAPI_Status __cdecl NvAPI_GPU_GetPCIIdentifiers(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pDeviceId, NvU32* pSubSystemId, NvU32* pRevisionId, NvU32* pExtDeviceId); 48 | NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName); 49 | NvAPI_Status __cdecl NvAPI_GPU_GetGpuCoreCount(NvPhysicalGpuHandle hPhysicalGpu, NvU32* pCount); 50 | NvAPI_Status __cdecl NvAPI_GPU_GetAllClockFrequencies(NvPhysicalGpuHandle hPhysicalGPU, NV_GPU_CLOCK_FREQUENCIES* pClkFreqs); 51 | NvAPI_Status __cdecl NvAPI_GPU_GetAdapterIdFromPhysicalGpu(NvPhysicalGpuHandle hPhysicalGpu, void* pOSAdapterId); 52 | NvAPI_Status __cdecl NvAPI_GPU_GetPstates20(NvPhysicalGpuHandle hPhysicalGpu, NV_GPU_PERF_PSTATES20_INFO* pPstatesInfo); 53 | NvAPI_Status __cdecl NvAPI_DISP_GetDisplayIdByDisplayName(const char* displayName, NvU32* displayId); 54 | NvAPI_Status __cdecl NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId); 55 | NvAPI_Status __cdecl NvAPI_Disp_SetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode); 56 | NvAPI_Status __cdecl NvAPI_Disp_GetOutputMode(NvU32 displayId, NV_DISPLAY_OUTPUT_MODE* pDisplayMode); 57 | NvAPI_Status __cdecl NvAPI_Disp_GetHdrCapabilities(NvU32 displayId, NV_HDR_CAPABILITIES *pHdrCapabilities); 58 | NvAPI_Status __cdecl NvAPI_Disp_HdrColorControl(NvU32 displayId, NV_HDR_COLOR_DATA *pHdrColorData); 59 | NvAPI_Status __cdecl NvAPI_Mosaic_GetDisplayViewportsByResolution(NvU32 displayId, NvU32 srcWidth, NvU32 srcHeight, NV_RECT viewports[NV_MOSAIC_MAX_DISPLAYS], NvU8* bezelCorrected); 60 | NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo); 61 | NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString); 62 | NvAPI_Status __cdecl NvAPI_SYS_GetDisplayIdFromGpuAndOutputId(NvPhysicalGpuHandle hPhysicalGpu, NvU32 outputId, NvU32* displayId); 63 | NvAPI_Status __cdecl NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(NvU32 displayId, NvPhysicalGpuHandle* hPhysicalGpu, NvU32* outputId); 64 | NvAPI_Status __cdecl NvAPI_D3D_GetObjectHandleForResource(IUnknown* invalid, IUnknown* pResource, NVDX_ObjectHandle* pHandle); 65 | NvAPI_Status __cdecl NvAPI_D3D_SetResourceHint(); 66 | NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams); 67 | NvAPI_Status __cdecl NvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams); 68 | NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); 69 | NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); 70 | NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice); 71 | NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams); 72 | NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported); 73 | NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext); 74 | NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext); 75 | NvAPI_Status __cdecl NvAPI_D3D11_SetDepthBoundsTest(IUnknown* pDeviceOrContext); 76 | NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingCaps(IUnknown* invalid, NVAPI_D3D12_RAYTRACING_CAPS_TYPE type, void* pData, size_t dataSize); 77 | NvAPI_Status __cdecl NvAPI_D3D12_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported); 78 | NvAPI_Status __cdecl NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread(); 79 | NvAPI_Status __cdecl NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx(ID3D12Device5* pDevice, NVAPI_GET_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO_EX_PARAMS* pParams); 80 | NvAPI_Status __cdecl NvAPI_D3D12_BuildRaytracingAccelerationStructureEx(ID3D12GraphicsCommandList4* pCommandList, const NVAPI_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_EX_PARAMS* pParams); 81 | NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType); 82 | NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams); 83 | NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session); 84 | NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session); 85 | NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session); 86 | NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile); 87 | NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting); 88 | NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting); 89 | NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session); 90 | NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk); 91 | NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown); 92 | NvAPI_Status __cdecl NvAPI_SK_1(IUnknown* unknown); 93 | NvAPI_Status __cdecl NvAPI_SK_2(IUnknown* unknown); 94 | NvAPI_Status __cdecl NvAPI_SK_3(IUnknown* unknown); 95 | NvAPI_Status __cdecl NvAPI_SK_4(IUnknown* unknown); 96 | NvAPI_Status __cdecl NvAPI_SK_5(IUnknown* unknown); 97 | NvAPI_Status __cdecl NvAPI_Unload(); 98 | NvAPI_Status __cdecl Fake_GetLatency(uint64_t* call_spot, uint64_t* wait_target, uint64_t* latency, uint64_t* frame_time); 99 | NvAPI_Status __cdecl Fake_InformFGState(bool fg_state); 100 | NvAPI_Status __cdecl Fake_InformPresentFG(bool frame_interpolated, uint64_t reflex_frame_id); 101 | #if _WIN64 102 | NvAPI_Status __cdecl Fake_GetAntiLagCtx(AMD::AntiLag2DX12::Context** al2_context); 103 | #endif 104 | } -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | NvAPI_Status Ok(const char* function_name) { 4 | spdlog::trace("{}: {}", function_name, "OK"); 5 | return NVAPI_OK; 6 | } 7 | 8 | NvAPI_Status Error(const char* function_name, NvAPI_Status status) { 9 | spdlog::trace("{}: {}", function_name, from_error_nr(status)); 10 | return status; 11 | } 12 | 13 | void prepare_logging(spdlog::level::level_enum level) { 14 | try { 15 | if (level != spdlog::level::off) { 16 | auto logger = spdlog::basic_logger_mt("basic_logger", "fakenvapi.log", true); 17 | spdlog::set_default_logger(std::move(logger)); 18 | if (level == spdlog::level::trace) 19 | spdlog::set_pattern("[%H:%M:%S.%f] [%L] [thread %t] %v"); 20 | else 21 | spdlog::set_pattern("[%H:%M:%S.%f] [%L] %v"); 22 | spdlog::set_level(level); 23 | spdlog::flush_on(level); 24 | } 25 | } catch (const spdlog::spdlog_ex &ex) { 26 | std::cout << "Log init failed: " << ex.what() << std::endl; 27 | } 28 | } 29 | 30 | void close_logging() { 31 | spdlog::default_logger()->flush(); 32 | spdlog::shutdown(); 33 | } 34 | 35 | void log_pcl(double pcl) { 36 | if (Config::get().get_save_pcl_to_file()) { 37 | std::ofstream output("pcl", std::ofstream::trunc); 38 | output << std::setprecision(2) << std::fixed << pcl; 39 | output.close(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "../external/nvapi.h" 6 | #include "spdlog/spdlog.h" 7 | #include "spdlog/sinks/basic_file_sink.h" 8 | #include "util.h" 9 | #include "config.h" 10 | 11 | #define OK() Ok(__func__) 12 | #undef ERROR 13 | #define ERROR() Error(__func__) 14 | #define ERROR_VALUE(status) Error(__func__, status) 15 | 16 | NvAPI_Status Ok(const char* function_name); 17 | NvAPI_Status Error(const char* function_name, NvAPI_Status status = NVAPI_ERROR); 18 | void prepare_logging(spdlog::level::level_enum level); 19 | void close_logging(); 20 | 21 | void log_pcl(double pcl); 22 | 23 | template 24 | void log_event(const char* event_name, std::format_string<_Args...> __fmt, _Args&&... __args) { 25 | spdlog::trace("EVENT,{},{},{}", event_name, get_timestamp(), std::vformat(__fmt.get(), std::make_format_args(__args...))); 26 | } 27 | -------------------------------------------------------------------------------- /src/lowlatency.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #if _MSC_VER 5 | #include 6 | #else 7 | #include "../external/d3d12.h" 8 | #endif 9 | 10 | #if _WIN64 11 | #include "../external/ffx_antilag2_dx12.h" 12 | #include "../external/ffx_antilag2_dx11.h" 13 | #endif 14 | 15 | #include "../external/latencyflex.h" 16 | 17 | #include "log.h" 18 | #include "config.h" 19 | 20 | enum class Mode { 21 | AntiLag2, 22 | LatencyFlex, 23 | }; 24 | 25 | enum class CallSpot { 26 | SleepCall = 0, 27 | InputSample = 1, 28 | SimulationStart = 2 29 | }; 30 | 31 | struct LFXStats { 32 | uint64_t latency = 0; 33 | uint64_t frame_time = 1; 34 | uint64_t target = 0; 35 | uint64_t frame_id = 0; 36 | bool needs_reset = false; 37 | }; 38 | 39 | struct FrameReport { 40 | NvU64 frameID; 41 | NvU64 inputSampleTime; 42 | NvU64 simStartTime; 43 | NvU64 simEndTime; 44 | NvU64 renderSubmitStartTime; 45 | NvU64 renderSubmitEndTime; 46 | NvU64 presentStartTime; 47 | NvU64 presentEndTime; 48 | NvU64 driverStartTime; 49 | NvU64 driverEndTime; 50 | NvU64 osRenderQueueStartTime; 51 | NvU64 osRenderQueueEndTime; 52 | NvU64 gpuRenderStartTime; 53 | NvU64 gpuRenderEndTime; 54 | NvU32 gpuActiveRenderTimeUs; 55 | NvU32 gpuFrameTimeUs; 56 | NvU8 rsvd[120]; 57 | }; 58 | 59 | class LowLatency { 60 | #if _WIN64 61 | Mode mode = Mode::AntiLag2; 62 | #else 63 | Mode mode = Mode::LatencyFlex; 64 | #endif 65 | lfx::LatencyFleX *lfx_ctx = nullptr; 66 | std::mutex lfx_mutex; 67 | std::mutex update_mutex; 68 | unsigned long min_interval_us = 0; 69 | bool al_available = false; 70 | bool force_latencyflex = false; 71 | ForceReflex force_reflex = ForceReflex::InGame; 72 | 73 | static constexpr uint64_t pcl_max_inprogress_frames = 16; 74 | uint64_t pcl_start_timestamps[pcl_max_inprogress_frames] = {}; 75 | uint64_t pcl_start_ids[pcl_max_inprogress_frames] = {}; 76 | 77 | // https://learn.microsoft.com/en-us/windows/win32/sync/using-waitable-timer-objects 78 | static inline int timer_sleep(int64_t hundred_ns){ 79 | static HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); 80 | LARGE_INTEGER due_time; 81 | 82 | due_time.QuadPart = -hundred_ns; 83 | 84 | if(!timer) 85 | return 1; 86 | 87 | if (!SetWaitableTimerEx(timer, &due_time, 0, NULL, NULL, NULL, 0)) 88 | return 2; 89 | 90 | if (WaitForSingleObject(timer, INFINITE) != WAIT_OBJECT_0) 91 | return 3; 92 | 93 | return 0; 94 | }; 95 | 96 | static inline int busywait_sleep(int64_t ns) { 97 | auto current_time = get_timestamp(); 98 | auto wait_until = current_time + ns; 99 | while (current_time < wait_until) { 100 | current_time = get_timestamp(); 101 | } 102 | return 0; 103 | } 104 | 105 | inline int eepy(int64_t ns) { 106 | constexpr int64_t busywait_threshold = 2000000; 107 | int status {}; 108 | auto current_time = get_timestamp(); 109 | if (ns <= busywait_threshold) 110 | status = busywait_sleep(ns); 111 | else 112 | status = timer_sleep((ns - busywait_threshold) / 100); 113 | 114 | if (int64_t sleep_deviation = ns - (get_timestamp() - current_time); sleep_deviation > 0 && !status) 115 | status = busywait_sleep(sleep_deviation); 116 | 117 | return status; 118 | } 119 | 120 | public: 121 | #if _WIN64 122 | AMD::AntiLag2DX12::Context al2_dx12_ctx = {}; 123 | AMD::AntiLag2DX11::Context al2_dx11_ctx = {}; 124 | #endif 125 | CallSpot call_spot = CallSpot::SleepCall; 126 | LFXStats lfx_stats = {}; 127 | LFXMode lfx_mode = {}; 128 | uint64_t calls_without_sleep = 0; 129 | FrameReport frame_reports[64]; 130 | bool fg = false; 131 | bool forced_fg = false; 132 | bool active = true; 133 | 134 | inline void init_al2(IUnknown *pDevice) { 135 | #if _WIN64 136 | if (mode == Mode::AntiLag2 && !al2_dx12_ctx.m_pAntiLagAPI && !al2_dx11_ctx.m_pAntiLagAPI) { 137 | ID3D12Device* device = nullptr; 138 | HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); 139 | if (hr == S_OK) { 140 | HRESULT init_return = AMD::AntiLag2DX12::Initialize(&al2_dx12_ctx, device); 141 | if (al_available = init_return == S_OK; !al_available) { 142 | mode = Mode::LatencyFlex; 143 | spdlog::info("AntiLag 2 DX12 initialization failed"); 144 | } else { 145 | spdlog::info("AntiLag 2 DX12 initialized"); 146 | } 147 | } else { 148 | HRESULT init_return = AMD::AntiLag2DX11::Initialize(&al2_dx11_ctx); 149 | if (al_available = init_return == S_OK; !al_available) { 150 | mode = Mode::LatencyFlex; 151 | spdlog::info("AntiLag 2 DX11 initialization failed"); 152 | } else { 153 | spdlog::info("AntiLag 2 DX11 initialized"); 154 | } 155 | } 156 | } 157 | #else 158 | al_available = false; 159 | #endif 160 | } 161 | 162 | inline void update_config() { 163 | force_latencyflex = Config::get().get_force_latencyflex(); 164 | force_reflex = Config::get().get_force_reflex(); 165 | lfx_mode = Config::get().get_latencyflex_mode(); 166 | } 167 | 168 | void init_lfx() { 169 | if (!lfx_ctx) { 170 | lfx_ctx = new lfx::LatencyFleX(); 171 | update_config(); 172 | spdlog::info("LatencyFleX initialized"); 173 | } 174 | } 175 | 176 | inline HRESULT update(uint64_t reflex_frame_id) { 177 | std::lock_guard lock(update_mutex); 178 | 179 | update_config(); 180 | 181 | log_event("update", "{}", reflex_frame_id); 182 | if (force_reflex == ForceReflex::ForceDisable || (force_reflex == ForceReflex::InGame && !active)) return S_FALSE; 183 | 184 | bool effective_fg_state = (fg || forced_fg); 185 | Mode previous_mode = mode; 186 | static bool previous_fg_status = effective_fg_state; 187 | static LFXMode previous_lfx_mode = lfx_mode; 188 | 189 | if (al_available && !force_latencyflex) 190 | mode = Mode::AntiLag2; 191 | else 192 | mode = Mode::LatencyFlex; 193 | 194 | if (previous_mode != mode) { 195 | spdlog::debug("Changed low latency algorithm to: {}", mode == Mode::AntiLag2 ? "AntiLag 2" : "LatencyFlex"); 196 | if (mode == Mode::LatencyFlex) 197 | lfx_stats.needs_reset = true; 198 | } 199 | 200 | if (previous_fg_status != effective_fg_state) { 201 | spdlog::info("FG mode changed to: {}", effective_fg_state ? "enabled" : "disabled"); 202 | lfx_stats.needs_reset = true; 203 | } 204 | previous_fg_status = effective_fg_state; 205 | 206 | if (previous_lfx_mode != lfx_mode) 207 | lfx_stats.needs_reset = true; 208 | previous_lfx_mode = lfx_mode; 209 | 210 | spdlog::debug("LowLatency algo: {}", mode == Mode::AntiLag2 ? "AntiLag 2" : "LatencyFlex"); 211 | spdlog::debug("FG status: {}", effective_fg_state ? "enabled" : "disabled"); 212 | 213 | if (mode == Mode::AntiLag2) { 214 | #if _WIN64 215 | if (lfx_stats.frame_id != 1) lfx_stats.needs_reset = true; 216 | int max_fps = 0; 217 | if ((fg || forced_fg) && min_interval_us != 0) { 218 | static uint64_t previous_frame_time = 0; 219 | uint64_t current_time = get_timestamp(); 220 | uint64_t frame_time = current_time - previous_frame_time; 221 | if (frame_time < 1000 * min_interval_us) { 222 | if (auto res = eepy(min_interval_us * 1000 - frame_time); res) 223 | spdlog::error("Sleep command failed: {}", res); 224 | } 225 | previous_frame_time = get_timestamp(); 226 | } else { 227 | max_fps = min_interval_us > 0 ? 1000000 / min_interval_us : 0; 228 | } 229 | HRESULT result = {}; 230 | auto pre_sleep = get_timestamp(); 231 | if (al2_dx12_ctx.m_pAntiLagAPI) 232 | result = AMD::AntiLag2DX12::Update(&al2_dx12_ctx, true, max_fps); 233 | else if (al2_dx11_ctx.m_pAntiLagAPI) 234 | result = AMD::AntiLag2DX11::Update(&al2_dx11_ctx, true, max_fps); 235 | log_event("al2_sleep", "{}", get_timestamp() - pre_sleep); 236 | return result; 237 | #endif 238 | } else if (mode == Mode::LatencyFlex) { 239 | if (lfx_stats.needs_reset) { 240 | spdlog::info("LFX Reset"); 241 | eepy(200000000ULL); 242 | lfx_stats.frame_id = 1; 243 | lfx_stats.needs_reset = false; 244 | lfx_ctx->Reset(); 245 | } 246 | uint64_t current_timestamp = get_timestamp(); 247 | uint64_t timestamp; 248 | 249 | // Set FPS Limiter 250 | lfx_ctx->target_frame_time = 1000 * min_interval_us; 251 | 252 | if (lfx_mode == LFXMode::Conservative) lfx_end_frame(0); // it should not be using this frame id in the conservative mode 253 | 254 | lfx_mutex.lock(); 255 | auto frame_id = lfx_mode == LFXMode::ReflexIDs ? reflex_frame_id : lfx_stats.frame_id + 1; 256 | log_event("lfx_get_wait_target", "{}", frame_id); 257 | lfx_stats.target = lfx_ctx->GetWaitTarget(frame_id); 258 | lfx_mutex.unlock(); 259 | 260 | if (lfx_stats.target > current_timestamp) { 261 | static uint64_t timeout_events = 0; 262 | uint64_t timeout_timestamp = current_timestamp + 50000000ULL; 263 | if (lfx_stats.target > timeout_timestamp) { 264 | log_event("lfx_target_high", "{}", lfx_stats.target - timeout_timestamp); 265 | timestamp = timeout_timestamp; 266 | timeout_events++; 267 | lfx_stats.needs_reset = timeout_events > 5; 268 | } else { 269 | timestamp = lfx_stats.target; 270 | timeout_events = 0; 271 | } 272 | log_event("lfx_sleep", "{}", timestamp - current_timestamp); 273 | if (auto res = eepy(timestamp - current_timestamp); res) 274 | spdlog::error("Sleep command failed: {}", res); 275 | } else { 276 | timestamp = current_timestamp; 277 | } 278 | 279 | lfx_mutex.lock(); 280 | lfx_stats.frame_id++; 281 | log_event("lfx_beginframe", "{}", frame_id); 282 | lfx_ctx->BeginFrame(frame_id, lfx_stats.target, timestamp); 283 | lfx_mutex.unlock(); 284 | 285 | return S_OK; 286 | } 287 | return S_FALSE; 288 | } 289 | 290 | inline HRESULT set_fg_type(bool interpolated, uint64_t reflex_frame_id) { 291 | #if _WIN64 292 | if (fg || forced_fg) { 293 | log_event("al2_set_fg_type", "{}", reflex_frame_id); 294 | return AMD::AntiLag2DX12::SetFrameGenFrameType(&al2_dx12_ctx, interpolated); 295 | } 296 | #endif 297 | return S_FALSE; 298 | } 299 | 300 | inline HRESULT mark_end_of_rendering(uint64_t reflex_frame_id) { 301 | #if _WIN64 302 | if (fg || forced_fg) { 303 | log_event("al2_end_of_rendering", "{}", reflex_frame_id); 304 | return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&al2_dx12_ctx); 305 | } 306 | #endif 307 | return S_FALSE; 308 | } 309 | 310 | inline void lfx_end_frame(uint64_t reflex_frame_id) { 311 | auto current_timestamp = get_timestamp(); 312 | lfx_mutex.lock(); 313 | auto frame_id = lfx_mode == LFXMode::ReflexIDs ? reflex_frame_id : lfx_stats.frame_id; 314 | log_event("lfx_endframe", "{}", frame_id); 315 | lfx_ctx->EndFrame(frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); 316 | lfx_mutex.unlock(); 317 | spdlog::debug("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp); 318 | } 319 | 320 | inline void pcl_start(uint64_t reflex_frame_id) { 321 | pcl_start_ids[reflex_frame_id % pcl_max_inprogress_frames] = reflex_frame_id; 322 | pcl_start_timestamps[reflex_frame_id % pcl_max_inprogress_frames] = get_timestamp(); 323 | } 324 | 325 | inline void pcl_end(uint64_t reflex_frame_id) { 326 | if (pcl_start_ids[reflex_frame_id % pcl_max_inprogress_frames] == reflex_frame_id) { 327 | pcl_start_ids[reflex_frame_id % pcl_max_inprogress_frames] = UINT64_MAX; 328 | double time_taken = get_timestamp() - pcl_start_timestamps[reflex_frame_id % pcl_max_inprogress_frames]; 329 | double time_taken_ms = time_taken / 1000000; 330 | log_pcl(time_taken_ms); 331 | } 332 | } 333 | 334 | void report_marker(NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { 335 | auto current_timestamp = get_timestamp() / 1000; 336 | static auto last_sim_start = current_timestamp; 337 | static auto _2nd_last_sim_start = current_timestamp; 338 | auto current_report = &frame_reports[pSetLatencyMarkerParams->frameID % 64]; 339 | current_report->frameID = pSetLatencyMarkerParams->frameID; 340 | current_report->gpuFrameTimeUs = last_sim_start - _2nd_last_sim_start; 341 | current_report->gpuActiveRenderTimeUs = 100; 342 | current_report->driverStartTime = current_timestamp; 343 | current_report->driverEndTime = current_timestamp + 100; 344 | current_report->gpuRenderStartTime = current_timestamp; 345 | current_report->gpuRenderEndTime = current_timestamp + 100; 346 | current_report->osRenderQueueStartTime = current_timestamp; 347 | current_report->osRenderQueueEndTime = current_timestamp + 100; 348 | switch (pSetLatencyMarkerParams->markerType) { 349 | case SIMULATION_START: 350 | _2nd_last_sim_start = last_sim_start; 351 | last_sim_start = get_timestamp() / 1000; 352 | current_report->simStartTime = last_sim_start; 353 | break; 354 | case SIMULATION_END: 355 | current_report->simEndTime = get_timestamp() / 1000; 356 | break; 357 | case RENDERSUBMIT_START: 358 | current_report->renderSubmitStartTime = get_timestamp() / 1000; 359 | break; 360 | case RENDERSUBMIT_END: 361 | current_report->renderSubmitEndTime = get_timestamp() / 1000; 362 | break; 363 | case PRESENT_START: 364 | current_report->presentStartTime = get_timestamp() / 1000; 365 | break; 366 | case PRESENT_END: 367 | current_report->presentEndTime = get_timestamp() / 1000; 368 | break; 369 | case INPUT_SAMPLE: 370 | current_report->inputSampleTime = get_timestamp() / 1000; 371 | break; 372 | default: 373 | break; 374 | } 375 | } 376 | 377 | inline void unload() { 378 | spdlog::info("Unloading lowlatency"); 379 | #if _WIN64 380 | if (al2_dx12_ctx.m_pAntiLagAPI && !AMD::AntiLag2DX12::DeInitialize(&al2_dx12_ctx)) 381 | spdlog::info("AntiLag 2 DX12 deinitialized"); 382 | if (al2_dx11_ctx.m_pAntiLagAPI && !AMD::AntiLag2DX11::DeInitialize(&al2_dx11_ctx)) 383 | spdlog::info("AntiLag 2 DX11 deinitialized"); 384 | #endif 385 | if (lfx_ctx) { 386 | delete lfx_ctx; 387 | lfx_ctx = nullptr; 388 | } 389 | spdlog::info("LatencyFlex deinitialized"); 390 | } 391 | 392 | void set_min_interval_us(unsigned long interval_us) { 393 | if (min_interval_us != interval_us) { 394 | min_interval_us = interval_us; 395 | spdlog::info("Changed max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0); 396 | } 397 | } 398 | 399 | Mode get_mode() { 400 | return mode; 401 | } 402 | }; -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include "../external/nvapi_interface.h" 6 | #if _MSC_VER 7 | #include 8 | #else 9 | #include "../external/d3d12.h" 10 | #endif 11 | #include "../external/nvapi.h" 12 | #include "fakenvapi.h" 13 | #include "../version.h" 14 | 15 | #include "log.h" 16 | #include "config.h" 17 | 18 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { 19 | switch (fdwReason) { 20 | case DLL_PROCESS_ATTACH: 21 | Config::get().init_config(); 22 | if (Config::get().get_enable_logs()) 23 | if (Config::get().get_enable_trace_logs()) 24 | prepare_logging(spdlog::level::trace); 25 | else 26 | prepare_logging(spdlog::level::info); 27 | else 28 | prepare_logging(spdlog::level::off); 29 | spdlog::critical("fakenvapi version: {}", FAKENVAPI_VERSION); 30 | spdlog::info("Config enable_trace_logs: {}", Config::get().get_enable_trace_logs() ? "true" : "false"); 31 | spdlog::info("Config force_latencyflex: {}", Config::get().get_force_latencyflex() ? "true" : "false"); 32 | spdlog::info("Config force_reflex: {}", (int)Config::get().get_force_reflex()); 33 | spdlog::info("Config lfx_mode: {}", (int)Config::get().get_latencyflex_mode()); 34 | spdlog::info("Config save_pcl_to_file: {}", Config::get().get_save_pcl_to_file() ? "true" : "false"); 35 | break; 36 | case DLL_PROCESS_DETACH: 37 | nvd::lowlatency_ctx.unload(); 38 | close_logging(); 39 | break; 40 | } 41 | return TRUE; 42 | } 43 | 44 | // names from: https://github.com/SveSop/nvapi_standalone/blob/master/dlls/nvapi/nvapi.c 45 | NVAPI_INTERFACE_TABLE additional_interface_table[] = { 46 | { "NvAPI_Diag_ReportCallStart", 0x33c7358c }, 47 | { "NvAPI_Diag_ReportCallReturn", 0x593e8644 }, 48 | { "NvAPI_Unknown_1", 0xe9b009b9 }, 49 | { "NvAPI_Vulkan_1", 0x17d13d6 }, 50 | { "NvAPI_SK_1", 0x57f7caac }, 51 | { "NvAPI_SK_2", 0x11104158 }, 52 | { "NvAPI_SK_3", 0xe3795199 }, 53 | { "NvAPI_SK_4", 0xdf0dfcdd }, 54 | { "NvAPI_SK_5", 0x932ac8fb }, 55 | { "Fake_GetLatency", 0x21372137 }, 56 | { "Fake_InformFGState", 0x21382138 }, 57 | { "Fake_InformPresentFG", 0x21392139 }, 58 | { "Fake_GetAntiLagCtx", 0x21402140 } 59 | }; 60 | 61 | namespace nvd { 62 | extern "C" { 63 | NvAPI_Status __cdecl placeholder() { 64 | // return OK(); 65 | // return ERROR(NVAPI_NO_IMPLEMENTATION); 66 | return NVAPI_NO_IMPLEMENTATION; // no logging 67 | } 68 | 69 | static std::unordered_map registry; 70 | 71 | __declspec(dllexport) void* __cdecl nvapi_QueryInterface(NvU32 id) { 72 | auto entry = registry.find(id); 73 | if (entry != registry.end()) 74 | return entry->second; 75 | 76 | constexpr auto table_size = sizeof(nvapi_interface_table)/sizeof(nvapi_interface_table[0]); 77 | struct NVAPI_INTERFACE_TABLE extended_interface_table[table_size + sizeof(additional_interface_table)/sizeof(additional_interface_table[0])] {}; 78 | memcpy(extended_interface_table, nvapi_interface_table, sizeof(nvapi_interface_table)); 79 | for (unsigned int i = 0; i < sizeof(additional_interface_table)/sizeof(additional_interface_table[0]); i++) { 80 | extended_interface_table[table_size + i] = additional_interface_table[i]; 81 | } 82 | 83 | auto it = std::find_if( 84 | std::begin(extended_interface_table), 85 | std::end(extended_interface_table), 86 | [id](const auto& item) { return item.id == id; }); 87 | 88 | if (it == std::end(extended_interface_table)) { 89 | spdlog::debug("NvAPI_QueryInterface (0x{:x}): Unknown interface ID", id); 90 | return registry.insert({ id, nullptr }).first->second; 91 | } 92 | 93 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Initialize) 94 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetInterfaceVersionString) 95 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_EnumNvidiaDisplayHandle) 96 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetLogicalGPUFromPhysicalGPU) 97 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_EnumPhysicalGPUs) 98 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_EnumLogicalGPUs) 99 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetGPUIDfromPhysicalGPU) 100 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetPhysicalGPUFromGPUID) 101 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetPhysicalGPUsFromDisplay) 102 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetPhysicalGPUsFromLogicalGPU) 103 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetErrorMessage) 104 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GetDisplayDriverVersion) 105 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetLogicalGpuInfo) 106 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetConnectedDisplayIds) 107 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_CudaEnumComputeCapableGpus) 108 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetArchInfo) 109 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetPCIIdentifiers) 110 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetFullName) 111 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetGpuCoreCount) 112 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetAllClockFrequencies) 113 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetAdapterIdFromPhysicalGpu) 114 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_GPU_GetPstates20) 115 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DISP_GetDisplayIdByDisplayName) 116 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DISP_GetGDIPrimaryDisplayId) 117 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Disp_SetOutputMode) 118 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Disp_GetOutputMode) 119 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Disp_GetHdrCapabilities) 120 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Disp_HdrColorControl) 121 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Mosaic_GetDisplayViewportsByResolution) 122 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SYS_GetDisplayDriverInfo) 123 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SYS_GetDriverAndBranchVersion) 124 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SYS_GetDisplayIdFromGpuAndOutputId) 125 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SYS_GetGpuAndOutputIdFromDisplayId) 126 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetResourceHint) 127 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetObjectHandleForResource) 128 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetSleepStatus) 129 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_GetLatency) 130 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetSleepMode) 131 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetLatencyMarker) 132 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_Sleep) 133 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetReflexSync) 134 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_IsNvShaderExtnOpCodeSupported) 135 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_BeginUAVOverlap) 136 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_EndUAVOverlap) 137 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_SetDepthBoundsTest) 138 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_GetRaytracingCaps) 139 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_IsNvShaderExtnOpCodeSupported) 140 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_SetNvShaderExtnSlotSpaceLocalThread) 141 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_GetRaytracingAccelerationStructurePrebuildInfoEx) 142 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_BuildRaytracingAccelerationStructureEx) 143 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_NotifyOutOfBandCommandQueue) 144 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_SetAsyncFrameMarker) 145 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_CreateSession) 146 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_LoadSettings) 147 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SaveSettings) 148 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetBaseProfile) 149 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetSetting) 150 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SetSetting) 151 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_DestroySession) 152 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unknown_1) 153 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_1) 154 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_1) 155 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_2) 156 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_3) 157 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_4) 158 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_SK_5) 159 | INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unload) 160 | INSERT_AND_RETURN_WHEN_EQUALS(Fake_GetLatency) 161 | INSERT_AND_RETURN_WHEN_EQUALS(Fake_InformFGState) 162 | INSERT_AND_RETURN_WHEN_EQUALS(Fake_InformPresentFG) 163 | #if _WIN64 164 | INSERT_AND_RETURN_WHEN_EQUALS(Fake_GetAntiLagCtx) 165 | #endif 166 | 167 | spdlog::debug("{}: not implemented, placeholder given", it->func); 168 | return registry.insert({ id, (void*)placeholder }).first->second; 169 | // return registry.insert({ id, nullptr }).first->second; 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | dll = shared_library( 2 | 'nvapi'+target_suffix, 3 | ['main.cpp', 'fakenvapi.cpp', 'util.cpp', 'log.cpp', fakenvapi_version], 4 | rc, 5 | name_prefix : '', 6 | dependencies : [ lib_dxgi ], 7 | include_directories: [ spdlog_headers ], 8 | install: true 9 | ) 10 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | void tonvss(NvAPI_ShortString nvss, std::string str) { 4 | str.resize(NVAPI_SHORT_STRING_MAX - 1); 5 | strcpy(nvss, str.c_str()); 6 | } 7 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../external/nvapi.h" 3 | #include 4 | #include 5 | #include 6 | #define WIN32_LEAN_AND_MEAN 7 | #include 8 | 9 | void tonvss(NvAPI_ShortString nvss, std::string str); 10 | 11 | #define INSERT_AND_RETURN_WHEN_EQUALS(method) \ 12 | if (std::string(it->func) == #method) \ 13 | return registry.insert({id, (void *)method}).first->second; 14 | 15 | static inline uint64_t get_timestamp() { 16 | FILETIME fileTime; 17 | GetSystemTimePreciseAsFileTime(&fileTime); 18 | 19 | uint64_t time = (static_cast(fileTime.dwHighDateTime) << 32) | fileTime.dwLowDateTime; 20 | 21 | return time * 100; 22 | } 23 | 24 | // function taken from jp7677's dxvk-nvapi project licensed under MIT 25 | inline std::string from_error_nr(const int16_t error_nr) { 26 | static const std::map errors{ 27 | {-1, "NVAPI_ERROR"}, 28 | {-2, "NVAPI_LIBRARY_NOT_FOUND"}, 29 | {-3, "NVAPI_NO_IMPLEMENTATION"}, 30 | {-4, "NVAPI_API_NOT_INITIALIZED"}, 31 | {-5, "NVAPI_INVALID_ARGUMENT"}, 32 | {-6, "NVAPI_NVIDIA_DEVICE_NOT_FOUND"}, 33 | {-7, "NVAPI_END_ENUMERATION"}, 34 | {-8, "NVAPI_INVALID_HANDLE"}, 35 | {-9, "NVAPI_INCOMPATIBLE_STRUCT_VERSION"}, 36 | {-10, "NVAPI_HANDLE_INVALIDATED"}, 37 | {-11, "NVAPI_OPENGL_CONTEXT_NOT_CURRENT"}, 38 | {-14, "NVAPI_INVALID_POINTER"}, 39 | {-12, "NVAPI_NO_GL_EXPERT"}, 40 | {-13, "NVAPI_INSTRUMENTATION_DISABLED"}, 41 | {-15, "NVAPI_NO_GL_NSIGHT"}, 42 | {-100, "NVAPI_EXPECTED_LOGICAL_GPU_HANDLE"}, 43 | {-101, "NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE"}, 44 | {-102, "NVAPI_EXPECTED_DISPLAY_HANDLE"}, 45 | {-103, "NVAPI_INVALID_COMBINATION"}, 46 | {-104, "NVAPI_NOT_SUPPORTED"}, 47 | {-105, "NVAPI_PORTID_NOT_FOUND"}, 48 | {-106, "NVAPI_EXPECTED_UNATTACHED_DISPLAY_HANDLE"}, 49 | {-107, "NVAPI_INVALID_PERF_LEVEL"}, 50 | {-108, "NVAPI_DEVICE_BUSY"}, 51 | {-109, "NVAPI_NV_PERSIST_FILE_NOT_FOUND"}, 52 | {-110, "NVAPI_PERSIST_DATA_NOT_FOUND"}, 53 | {-111, "NVAPI_EXPECTED_TV_DISPLAY"}, 54 | {-112, "NVAPI_EXPECTED_TV_DISPLAY_ON_DCONNECTOR"}, 55 | {-113, "NVAPI_NO_ACTIVE_SLI_TOPOLOGY"}, 56 | {-114, "NVAPI_SLI_RENDERING_MODE_NOTALLOWED"}, 57 | {-115, "NVAPI_EXPECTED_DIGITAL_FLAT_PANEL"}, 58 | {-116, "NVAPI_ARGUMENT_EXCEED_MAX_SIZE"}, 59 | {-117, "NVAPI_DEVICE_SWITCHING_NOT_ALLOWED"}, 60 | {-118, "NVAPI_TESTING_CLOCKS_NOT_SUPPORTED"}, 61 | {-119, "NVAPI_UNKNOWN_UNDERSCAN_CONFIG"}, 62 | {-120, "NVAPI_TIMEOUT_RECONFIGURING_GPU_TOPO"}, 63 | {-121, "NVAPI_DATA_NOT_FOUND"}, 64 | {-122, "NVAPI_EXPECTED_ANALOG_DISPLAY"}, 65 | {-123, "NVAPI_NO_VIDLINK"}, 66 | {-124, "NVAPI_REQUIRES_REBOOT"}, 67 | {-125, "NVAPI_INVALID_HYBRID_MODE"}, 68 | {-126, "NVAPI_MIXED_TARGET_TYPES"}, 69 | {-127, "NVAPI_SYSWOW64_NOT_SUPPORTED"}, 70 | {-128, "NVAPI_IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED"}, 71 | {-129, "NVAPI_REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS"}, 72 | {-130, "NVAPI_OUT_OF_MEMORY"}, 73 | {-131, "NVAPI_WAS_STILL_DRAWING"}, 74 | {-132, "NVAPI_FILE_NOT_FOUND"}, 75 | {-133, "NVAPI_TOO_MANY_UNIQUE_STATE_OBJECTS"}, 76 | {-134, "NVAPI_INVALID_CALL"}, 77 | {-135, "NVAPI_D3D10_1_LIBRARY_NOT_FOUND"}, 78 | {-136, "NVAPI_FUNCTION_NOT_FOUND"}, 79 | {-137, "NVAPI_INVALID_USER_PRIVILEGE"}, 80 | {-138, "NVAPI_EXPECTED_NON_PRIMARY_DISPLAY_HANDLE"}, 81 | {-139, "NVAPI_EXPECTED_COMPUTE_GPU_HANDLE"}, 82 | {-140, "NVAPI_STEREO_NOT_INITIALIZED"}, 83 | {-141, "NVAPI_STEREO_REGISTRY_ACCESS_FAILED"}, 84 | {-142, "NVAPI_STEREO_REGISTRY_PROFILE_TYPE_NOT_SUPPORTED"}, 85 | {-143, "NVAPI_STEREO_REGISTRY_VALUE_NOT_SUPPORTED"}, 86 | {-144, "NVAPI_STEREO_NOT_ENABLED"}, 87 | {-145, "NVAPI_STEREO_NOT_TURNED_ON"}, 88 | {-146, "NVAPI_STEREO_INVALID_DEVICE_INTERFACE"}, 89 | {-147, "NVAPI_STEREO_PARAMETER_OUT_OF_RANGE"}, 90 | {-148, "NVAPI_STEREO_FRUSTUM_ADJUST_MODE_NOT_SUPPORTED"}, 91 | {-149, "NVAPI_TOPO_NOT_POSSIBLE"}, 92 | {-150, "NVAPI_MODE_CHANGE_FAILED"}, 93 | {-151, "NVAPI_D3D11_LIBRARY_NOT_FOUND"}, 94 | {-152, "NVAPI_INVALID_ADDRESS"}, 95 | {-153, "NVAPI_STRING_TOO_SMALL"}, 96 | {-154, "NVAPI_MATCHING_DEVICE_NOT_FOUND"}, 97 | {-155, "NVAPI_DRIVER_RUNNING"}, 98 | {-156, "NVAPI_DRIVER_NOTRUNNING"}, 99 | {-157, "NVAPI_ERROR_DRIVER_RELOAD_REQUIRED"}, 100 | {-158, "NVAPI_SET_NOT_ALLOWED"}, 101 | {-159, "NVAPI_ADVANCED_DISPLAY_TOPOLOGY_REQUIRED"}, 102 | {-160, "NVAPI_SETTING_NOT_FOUND"}, 103 | {-161, "NVAPI_SETTING_SIZE_TOO_LARGE"}, 104 | {-162, "NVAPI_TOO_MANY_SETTINGS_IN_PROFILE"}, 105 | {-163, "NVAPI_PROFILE_NOT_FOUND"}, 106 | {-164, "NVAPI_PROFILE_NAME_IN_USE"}, 107 | {-165, "NVAPI_PROFILE_NAME_EMPTY"}, 108 | {-166, "NVAPI_EXECUTABLE_NOT_FOUND"}, 109 | {-167, "NVAPI_EXECUTABLE_ALREADY_IN_USE"}, 110 | {-168, "NVAPI_DATATYPE_MISMATCH"}, 111 | {-169, "NVAPI_PROFILE_REMOVED"}, 112 | {-170, "NVAPI_UNREGISTERED_RESOURCE"}, 113 | {-171, "NVAPI_ID_OUT_OF_RANGE"}, 114 | {-172, "NVAPI_DISPLAYCONFIG_VALIDATION_FAILED"}, 115 | {-173, "NVAPI_DPMST_CHANGED"}, 116 | {-174, "NVAPI_INSUFFICIENT_BUFFER"}, 117 | {-175, "NVAPI_ACCESS_DENIED"}, 118 | {-176, "NVAPI_MOSAIC_NOT_ACTIVE"}, 119 | {-177, "NVAPI_SHARE_RESOURCE_RELOCATED"}, 120 | {-178, "NVAPI_REQUEST_USER_TO_DISABLE_DWM"}, 121 | {-179, "NVAPI_D3D_DEVICE_LOST"}, 122 | {-180, "NVAPI_INVALID_CONFIGURATION"}, 123 | {-181, "NVAPI_STEREO_HANDSHAKE_NOT_DONE"}, 124 | {-182, "NVAPI_EXECUTABLE_PATH_IS_AMBIGUOUS"}, 125 | {-183, "NVAPI_DEFAULT_STEREO_PROFILE_IS_NOT_DEFINED"}, 126 | {-184, "NVAPI_DEFAULT_STEREO_PROFILE_DOES_NOT_EXIST"}, 127 | {-185, "NVAPI_CLUSTER_ALREADY_EXISTS"}, 128 | {-186, "NVAPI_DPMST_DISPLAY_ID_EXPECTED"}, 129 | {-187, "NVAPI_INVALID_DISPLAY_ID"}, 130 | {-188, "NVAPI_STREAM_IS_OUT_OF_SYNC"}, 131 | {-189, "NVAPI_INCOMPATIBLE_AUDIO_DRIVER"}, 132 | {-190, "NVAPI_VALUE_ALREADY_SET"}, 133 | {-191, "NVAPI_TIMEOUT"}, 134 | {-192, "NVAPI_GPU_WORKSTATION_FEATURE_INCOMPLETE"}, 135 | {-193, "NVAPI_STEREO_INIT_ACTIVATION_NOT_DONE"}, 136 | {-194, "NVAPI_SYNC_NOT_ACTIVE"}, 137 | {-195, "NVAPI_SYNC_MASTER_NOT_FOUND"}, 138 | {-196, "NVAPI_INVALID_SYNC_TOPOLOGY"}, 139 | {-197, "NVAPI_ECID_SIGN_ALGO_UNSUPPORTED"}, 140 | {-198, "NVAPI_ECID_KEY_VERIFICATION_FAILED"}, 141 | {-199, "NVAPI_FIRMWARE_OUT_OF_DATE"}, 142 | {-200, "NVAPI_FIRMWARE_REVISION_NOT_SUPPORTED"}, 143 | {-201, "NVAPI_LICENSE_CALLER_AUTHENTICATION_FAILED"}, 144 | {-202, "NVAPI_D3D_DEVICE_NOT_REGISTERED"}, 145 | {-203, "NVAPI_RESOURCE_NOT_ACQUIRED"}, 146 | {-204, "NVAPI_TIMING_NOT_SUPPORTED"}, 147 | {-205, "NVAPI_HDCP_ENCRYPTION_FAILED"}, 148 | {-206, "NVAPI_PCLK_LIMITATION_FAILED"}, 149 | {-207, "NVAPI_NO_CONNECTOR_FOUND"}, 150 | {-208, "NVAPI_HDCP_DISABLED"}, 151 | {-209, "NVAPI_API_IN_USE"}, 152 | {-210, "NVAPI_NVIDIA_DISPLAY_NOT_FOUND"}, 153 | {-211, "NVAPI_PRIV_SEC_VIOLATION"}, 154 | {-212, "NVAPI_INCORRECT_VENDOR"}, 155 | {-213, "NVAPI_DISPLAY_IN_USE"}, 156 | {-214, "NVAPI_UNSUPPORTED_CONFIG_NON_HDCP_HMD"}, 157 | {-215, "NVAPI_MAX_DISPLAY_LIMIT_REACHED"}, 158 | {-216, "NVAPI_INVALID_DIRECT_MODE_DISPLAY"}, 159 | {-217, "NVAPI_GPU_IN_DEBUG_MODE"}, 160 | {-218, "NVAPI_D3D_CONTEXT_NOT_FOUND"}, 161 | {-219, "NVAPI_STEREO_VERSION_MISMATCH"}, 162 | {-220, "NVAPI_GPU_NOT_POWERED"}, 163 | {-221, "NVAPI_ERROR_DRIVER_RELOAD_IN_PROGRESS"}, 164 | {-222, "NVAPI_WAIT_FOR_HW_RESOURCE"}, 165 | {-223, "NVAPI_REQUIRE_FURTHER_HDCP_ACTION"}, 166 | {-224, "NVAPI_DISPLAY_MUX_TRANSITION_FAILED"} }; 167 | 168 | auto it = errors.find(error_nr); 169 | return it != errors.end() ? it->second : "UNKNOWN_ERROR"; 170 | } 171 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define FAKENVAPI_VERSION "@VCS_TAG@" --------------------------------------------------------------------------------