diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.cpp b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp old mode 100755 new mode 100644 similarity index 77% rename from OptiScaler/nvapi/fakenvapi/nvapi.cpp rename to OptiScaler/nvapi/fakenvapi/fakenvapi.cpp index 593376d8..bbfb75e2 --- a/OptiScaler/nvapi/fakenvapi/nvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi/fakenvapi.cpp @@ -1,24 +1,24 @@ -#include "nvapi.h" +#include "fakenvapi.h" #include namespace nvd { NvAPI_Status __cdecl NvAPI_Initialize() { IDXGIFactory1* pFactory = nullptr; if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { - log("Failed to create DXGI Factory"); + spdlog::error("Failed to create DXGI Factory"); return Error(); } IDXGIAdapter1* pAdapter = nullptr; if (FAILED(pFactory->EnumAdapters1(0, &pAdapter))) { - log("Failed to enumerate adapters"); + spdlog::error("Failed to enumerate adapters"); pFactory->Release(); return Error(); } DXGI_ADAPTER_DESC1 adapterDesc; if (FAILED(pAdapter->GetDesc1(&adapterDesc))) { - log("Failed to get adapter description"); + spdlog::error("Failed to get adapter description"); pAdapter->Release(); pFactory->Release(); return Error(); @@ -33,6 +33,8 @@ namespace nvd { pAdapter->Release(); pFactory->Release(); + lowlatency_ctx.init_lfx(); + return Ok(); } @@ -57,7 +59,7 @@ namespace nvd { if (displayId == 0) { return Ok(); } - return Error(NVAPI_NVIDIA_DISPLAY_NOT_FOUND); + return Error(NVAPI_END_ENUMERATION); } NvAPI_Status __cdecl NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle physicalHandle, NvLogicalGpuHandle* logicalHandle) { @@ -85,7 +87,7 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_GetErrorMessage(NvAPI_Status status, NvAPI_ShortString szMsg) { std::string error = fromErrorNr(status); - log(std::format("NvAPI_GetErrorMessage gave this error: {}", error)); + spdlog::error("NvAPI_GetErrorMessage gave this error: {}", error); tonvss(szMsg, error); return Ok(); } @@ -105,12 +107,12 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_GPU_GetArchInfo(NvPhysicalGpuHandle handle, NV_GPU_ARCH_INFO* archInfo) { - archInfo->architecture = spoof::arch; - archInfo->architecture_id = spoof::arch; - archInfo->implementation = spoof::implementation; - archInfo->implementation_id = spoof::implementation; - archInfo->revision = spoof::revision; - archInfo->revision_id = spoof::revision; + archInfo->architecture = NV_GPU_ARCHITECTURE_AD100; + archInfo->architecture_id = NV_GPU_ARCHITECTURE_AD100; + archInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_AD102; + archInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_AD102; + archInfo->revision = NV_GPU_CHIP_REV_UNKNOWN; + archInfo->revision_id = NV_GPU_CHIP_REV_UNKNOWN; return Ok(); } @@ -131,7 +133,7 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName) { - tonvss(szName, spoof::fullGPUName); + tonvss(szName, "NVIDIA GeForce RTX 4090"); return Ok(); } @@ -262,15 +264,19 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_SYS_GetDisplayDriverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { - spoof::driverInfo(driverInfo); + driverInfo->driverVersion = 99999; + tonvss(driverInfo->szBuildBranch, "buildBranch"); + driverInfo->bIsDCHDriver = 1; + driverInfo->bIsNVIDIAStudioPackage = 1; + driverInfo->bIsNVIDIARTXProductionBranchPackage = 1; + driverInfo->bIsNVIDIARTXNewFeatureBranchPackage = 1; + if (driverInfo->version == 2) + tonvss(driverInfo->szBuildBaseBranch, "buildBaseBranch"); return Ok(); } NvAPI_Status __cdecl NvAPI_SYS_GetDriverAndBranchVersion(NvU32* pDriverVersion, NvAPI_ShortString szBuildBranchString) { - memset(pDriverVersion, 0, sizeof(NvU32)); - memcpy(pDriverVersion, &spoof::driverVersion, sizeof(NvU32)); - // *pDriverVersion = spoof::driverVersion; - tonvss(szBuildBranchString, spoof::buildBranch); + tonvss(szBuildBranchString, "buildBranch"); return Ok(); } @@ -295,6 +301,9 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_GetSleepStatus(IUnknown* pDevice, NV_GET_SLEEP_STATUS_PARAMS* pGetSleepStatusParams) { + pGetSleepStatusParams->bLowLatencyMode = lowlatency_ctx.active; + pGetSleepStatusParams->bFsVrr = true; + pGetSleepStatusParams->bCplVsyncOn = true; return Ok(); } @@ -303,14 +312,46 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams) { + lowlatency_ctx.active = pSetSleepModeParams->bLowLatencyMode; +#ifdef TESTING + lowlatency_ctx.force_lfx = pSetSleepModeParams->bLowLatencyBoost; +#endif + lowlatency_ctx.set_min_interval_us(pSetSleepModeParams->minimumIntervalUs); return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams) { + if (!pDev) + return Error(); + spdlog::debug("markerType: {}, frame id: {}", (unsigned int)pSetLatencyMarkerParams->markerType, (unsigned long long)pSetLatencyMarkerParams->frameID); + lowlatency_ctx.init_al2(pDev); + switch (pSetLatencyMarkerParams->markerType) { + case SIMULATION_START: + if (lowlatency_ctx.call_spot != SimulationStart) break; + spdlog::debug("LowLatency update called on simulation start with result: {}", lowlatency_ctx.update()); + break; + case INPUT_SAMPLE: + if (lowlatency_ctx.call_spot == SleepCall) break; + lowlatency_ctx.call_spot = InputSample; + spdlog::debug("LowLatency update called on input sample with result: {}", lowlatency_ctx.update()); + break; + case PRESENT_START: + if (lowlatency_ctx.fg) lowlatency_ctx.mark_end_of_rendering(); + break; + } return Ok(); } NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice) { + if (!pDevice) + return Error(); + lowlatency_ctx.init_al2(pDevice); + lowlatency_ctx.call_spot = SleepCall; + spdlog::debug("LowLatency update called on sleep with result: {}", lowlatency_ctx.update()); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams) { return Ok(); } @@ -390,6 +431,7 @@ namespace nvd { return Ok(); } + // Taken directly from dxvk-nvapi static bool ConvertBuildRaytracingAccelerationStructureInputs(const NVAPI_D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS_EX* nvDesc, std::vector& geometryDescs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS* d3dDesc) { d3dDesc->Type = nvDesc->type; // assume that OMM via VK_EXT_opacity_micromap and DMM via VK_NV_displacement_micromap are not supported, allow only standard flags to be passed @@ -426,13 +468,13 @@ namespace nvd { d3dGeoDesc.AABBs = nvGeoDesc.aabbs; break; case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_OMM_TRIANGLES_EX: // GetRaytracingCaps reports no OMM caps, we shouldn't reach this - log("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); + spdlog::error("Triangles with OMM attachment passed to acceleration structure build when OMM is not supported"); return false; case NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_DMM_TRIANGLES_EX: // GetRaytracingCaps reports no DMM caps, we shouldn't reach this - log("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); + spdlog::error("Triangles with DMM attachment passed to acceleration structure build when DMM is not supported"); return false; default: - log("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); + spdlog::error("Unknown NVAPI_D3D12_RAYTRACING_GEOMETRY_TYPE_EX"); return false; } } @@ -468,7 +510,12 @@ namespace nvd { return Error(NVAPI_INVALID_ARGUMENT); pCommandList->BuildRaytracingAccelerationStructure(&desc, pParams->numPostbuildInfoDescs, pParams->pPostbuildInfoDescs); - return Ok(); + static bool logged = false; + if (!logged) { + logged = true; + return Ok(); + } + else return NVAPI_OK; //return without logging } NvAPI_Status __cdecl NvAPI_D3D12_NotifyOutOfBandCommandQueue(ID3D12CommandQueue* pCommandQueue, NV_OUT_OF_BAND_CQ_TYPE cqType) { @@ -476,6 +523,30 @@ namespace nvd { } NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams) { + if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START) { + constexpr unsigned int history_size = 10; + static NvU64 counter = 0; + static NvU64 previous_frame_ids[history_size] = {}; + static NvU64 previous_frame_id = 0; + NvU64 current_frame_id = pSetAsyncFrameMarkerParams->frameID; + + previous_frame_ids[counter%history_size] = current_frame_id; + counter++; + + std::unordered_set seen; + unsigned int repeat_count = 0; + for (const NvU64& frame_id : previous_frame_ids) { + if (seen.contains(frame_id)) repeat_count++; + else seen.insert(frame_id); + } + + if (lowlatency_ctx.fg && repeat_count == 0) lowlatency_ctx.fg = false; + else if (!lowlatency_ctx.fg && repeat_count >= history_size / 2) lowlatency_ctx.fg = true; + + if (lowlatency_ctx.fg) lowlatency_ctx.set_fg_type(previous_frame_id == current_frame_id); + previous_frame_id = current_frame_id; + } + spdlog::debug("Async markerType: {}, frame id: {}", (unsigned int)pSetAsyncFrameMarkerParams->markerType, (unsigned long long)pSetAsyncFrameMarkerParams->frameID); return Ok(); } @@ -488,30 +559,57 @@ namespace nvd { return Ok(); } + NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session) { + return Ok(); + } + NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile) { *profile = drsProfile; return Ok(); } NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting) { - log(std::format("Missing setting: {}", settingId)); - return Error(NVAPI_SETTING_NOT_FOUND); + spdlog::debug("Missing get setting: {}", settingId); + return Ok(); + } + + NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting) { + spdlog::debug("Missing set setting: {}", pSetting->settingId); + return Ok(); } NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session) { return Ok(); } - NvAPI_Status __cdecl NvAPI_Unload() { - return Ok(); - } - - NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk) { + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk) { std::fill(pMiscUnk, pMiscUnk + 4, 0x1); return Ok(); } - NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown) { + NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown) { return Ok(); } + + NvAPI_Status __cdecl NvAPI_Unload() { + lowlatency_ctx.unload(); + return Ok(); + } + + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* target, uint64_t* latency, uint64_t* frame_time) { +#if _MSC_VER && _WIN64 + if (!call_spot || !target || !latency || !frame_time) return Error(NVAPI_INVALID_POINTER); + + if (lowlatency_ctx.get_mode() != LatencyFlex) return Error(NVAPI_DATA_NOT_FOUND); + *call_spot = (uint64_t)lowlatency_ctx.call_spot; + + *target = lowlatency_ctx.lfx_stats.target; + *latency = lowlatency_ctx.lfx_stats.latency; + *frame_time = lowlatency_ctx.lfx_stats.frame_time; + + return Ok(); +#else + return Error(NVAPI_DATA_NOT_FOUND); +#endif + } } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/nvapi.h b/OptiScaler/nvapi/fakenvapi/fakenvapi.h old mode 100755 new mode 100644 similarity index 90% rename from OptiScaler/nvapi/fakenvapi/nvapi.h rename to OptiScaler/nvapi/fakenvapi/fakenvapi.h index b7828dde..fea0b362 --- a/OptiScaler/nvapi/fakenvapi/nvapi.h +++ b/OptiScaler/nvapi/fakenvapi/fakenvapi.h @@ -1,6 +1,8 @@ #pragma once #include #include +#include +#include #include #include @@ -11,8 +13,9 @@ #endif #include +#include "lowlatency.h" + #include "util.h" -#include "spoofInfo.h" #include "log.h" namespace nvd { @@ -20,13 +23,14 @@ namespace nvd { static auto drsSession = reinterpret_cast(&drs); static auto drsProfile = reinterpret_cast(&drs); - static LUID luid; static UINT deviceId; static UINT vendorId; static UINT subSysId; static UINT revisionId; + static LowLatency lowlatency_ctx; + NvAPI_Status __cdecl NvAPI_Initialize(); NvAPI_Status __cdecl NvAPI_GetInterfaceVersionString(NvAPI_ShortString desc); NvAPI_Status __cdecl NvAPI_EnumPhysicalGPUs(NvPhysicalGpuHandle handles[NVAPI_MAX_PHYSICAL_GPUS], NvU32* count); @@ -63,6 +67,7 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D_SetSleepMode(IUnknown* pDevice, NV_SET_SLEEP_MODE_PARAMS* pSetSleepModeParams); NvAPI_Status __cdecl NvAPI_D3D_SetLatencyMarker(IUnknown* pDev, NV_LATENCY_MARKER_PARAMS* pSetLatencyMarkerParams); NvAPI_Status __cdecl NvAPI_D3D_Sleep(IUnknown* pDevice); + NvAPI_Status __cdecl NvAPI_D3D_SetReflexSync(IUnknown* pDev, NV_SET_REFLEX_SYNC_PARAMS* pSetReflexSyncParams); NvAPI_Status __cdecl NvAPI_D3D11_IsNvShaderExtnOpCodeSupported(IUnknown* invalid, NvU32 opCode, bool* pSupported); NvAPI_Status __cdecl NvAPI_D3D11_BeginUAVOverlap(IUnknown* pDeviceOrContext); NvAPI_Status __cdecl NvAPI_D3D11_EndUAVOverlap(IUnknown* pDeviceOrContext); @@ -76,10 +81,13 @@ namespace nvd { NvAPI_Status __cdecl NvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, NV_ASYNC_FRAME_MARKER_PARAMS* pSetAsyncFrameMarkerParams); NvAPI_Status __cdecl NvAPI_DRS_CreateSession(NvDRSSessionHandle* session); NvAPI_Status __cdecl NvAPI_DRS_LoadSettings(NvDRSSessionHandle session); + NvAPI_Status __cdecl NvAPI_DRS_SaveSettings(NvDRSSessionHandle session); NvAPI_Status __cdecl NvAPI_DRS_GetBaseProfile(NvDRSSessionHandle session, NvDRSProfileHandle* profile); NvAPI_Status __cdecl NvAPI_DRS_GetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NvU32 settingId, NVDRS_SETTING* pSetting); + NvAPI_Status __cdecl NvAPI_DRS_SetSetting(NvDRSSessionHandle hSession, NvDRSProfileHandle hProfile, NVDRS_SETTING *pSetting); NvAPI_Status __cdecl NvAPI_DRS_DestroySession(NvDRSSessionHandle session); + NvAPI_Status __cdecl NvAPI_Unknown_1(IUnknown* unknown, uint32_t* pMiscUnk); + NvAPI_Status __cdecl NvAPI_Vulkan_1(IUnknown* unknown); NvAPI_Status __cdecl NvAPI_Unload(); - NvAPI_Status __cdecl MISC_unknown(IUnknown* unknown, uint32_t* pMiscUnk); - NvAPI_Status __cdecl MISC_vulkan(IUnknown* unknown); + NvAPI_Status __cdecl Dummy_GetLatency(uint64_t* call_spot, uint64_t* waitTarget, uint64_t* latency, uint64_t* frameTime); } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/log.cpp b/OptiScaler/nvapi/fakenvapi/log.cpp index 254c46f1..6b530ecf 100644 --- a/OptiScaler/nvapi/fakenvapi/log.cpp +++ b/OptiScaler/nvapi/fakenvapi/log.cpp @@ -1,52 +1,43 @@ -#include "log.h" - -std::ostream null(nullptr); -std::ostream* logStream = &null; -std::ofstream fileStream; - -std::string getCurrentTimeFormatted() { - auto now = std::chrono::system_clock::now(); - auto now_t = std::chrono::system_clock::to_time_t(now); - auto now_tm = *std::localtime(&now_t); - auto now_duration = now - std::chrono::system_clock::from_time_t(std::mktime(&now_tm)); - auto now_us = std::chrono::duration_cast(now_duration); - std::ostringstream oss; - oss << std::setfill('0') << std::setw(2) << now_tm.tm_hour << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_min << ":" - << std::setfill('0') << std::setw(2) << now_tm.tm_sec << "." - << std::setfill('0') << std::setw(6) << now_us.count(); - - return oss.str(); -} - -void log(const std::string& log) { - *logStream << "[" << getCurrentTimeFormatted() << "] " << log << std::endl; -} - -NvAPI_Status Ok(const std::source_location& location) { - log(std::format("{}: {}", location.function_name(), "OK")); - return NVAPI_OK; -} - -NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { - log(std::format("{}: {}", location.function_name(), fromErrorNr(status))); - return status; -} - -void prepareLogging(std::optional fileName) { - if (fileName.has_value()) { - fileStream.open(fileName.value(), std::ios_base::out | std::ios_base::app); - if (fileStream.is_open()) { - logStream = &fileStream; - return; - } - else { - std::cerr << "Failed to open log file: " << fileName.value() << std::endl; - } - } - // logStream = &std::cout; -} - -void closeLogging() { - fileStream.close(); +#include "log.h" + +inline std::string extractFunctionName(const std::string& signature) { + size_t start = signature.find("nvd::"); + if (start == std::string::npos) return {}; + start += 5; + size_t end = signature.find('(', start); + if (end == std::string::npos) return {}; + + return signature.substr(start, end - start); +} + +NvAPI_Status Ok(const std::source_location& location) { + spdlog::trace("{}: {}", extractFunctionName(location.function_name()), "OK"); + return NVAPI_OK; +} + +NvAPI_Status Error(NvAPI_Status status, const std::source_location& location) { + spdlog::trace("{}: {}", extractFunctionName(location.function_name()), fromErrorNr(status)); + return status; +} + +void prepareLogging(spdlog::level::level_enum level) { + try { + if (level != spdlog::level::off) { + auto logger = spdlog::basic_logger_mt("basic_logger", "fakenvapi.log"); + spdlog::set_default_logger(logger); + if (level == spdlog::level::trace) + spdlog::set_pattern("[%H:%M:%S.%f] [%L] [thread %t] %v"); + else + spdlog::set_pattern("[%H:%M:%S.%f] [%L] %v"); + spdlog::set_level(level); + spdlog::flush_on(level); + } + } catch (const spdlog::spdlog_ex &ex) { + std::cout << "Log init failed: " << ex.what() << std::endl; + } +} + +void closeLogging() { + spdlog::default_logger()->flush(); + spdlog::shutdown(); } \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/log.h b/OptiScaler/nvapi/fakenvapi/log.h old mode 100644 new mode 100755 index 96465672..8e7ebf1d --- a/OptiScaler/nvapi/fakenvapi/log.h +++ b/OptiScaler/nvapi/fakenvapi/log.h @@ -7,11 +7,11 @@ #include #include #include "util.h" -#include "../include/nvapi.h" +#include "../external/nvapi.h" +#include "spdlog/spdlog.h" +#include "spdlog/sinks/basic_file_sink.h" -std::string getCurrentTimeFormatted(); -void log(const std::string& log); NvAPI_Status Ok(const std::source_location &location = std::source_location::current()); NvAPI_Status Error(NvAPI_Status status = NVAPI_ERROR, const std::source_location &location = std::source_location::current()); -void prepareLogging(std::optional fileName); +void prepareLogging(spdlog::level::level_enum level); void closeLogging(); diff --git a/OptiScaler/nvapi/fakenvapi/lowlatency.h b/OptiScaler/nvapi/fakenvapi/lowlatency.h new file mode 100644 index 00000000..436d6ee3 --- /dev/null +++ b/OptiScaler/nvapi/fakenvapi/lowlatency.h @@ -0,0 +1,186 @@ +#pragma once + +#include + +#include +#if defined __MINGW64__ || defined __MINGW32__ +#include "../external/d3d12.h" +#else +#include +#endif + +#if _MSC_VER && _WIN64 +#include "../external/ffx_antilag2_dx12.h" +#include "../external/ffx_antilag2_dx11.h" +#endif + +#include "../external/latencyflex.h" + +#include "log.h" + +enum Mode { + AntiLag2, + LatencyFlex, +}; + +enum CallSpot { + SleepCall = 0, + InputSample = 1, + SimulationStart = 2 +}; + +struct LFXStats { + uint64_t latency = 0; + uint64_t frame_time = 1; + uint64_t target = 0; + uint64_t frame_id = 0; + bool needs_reset = false; +}; + +class LowLatency { +#if _MSC_VER && _WIN64 + AMD::AntiLag2DX12::Context context_dx12 = {}; + AMD::AntiLag2DX11::Context context_dx11 = {}; + Mode mode = AntiLag2; +#else + Mode mode = LatencyFlex; +#endif + lfx::LatencyFleX *lf; + unsigned long min_interval_us = 0; + bool al_available = false; + + static inline uint64_t GetTimestamp() { + LARGE_INTEGER frequency; + LARGE_INTEGER counter; + + QueryPerformanceFrequency(&frequency); + QueryPerformanceCounter(&counter); + return static_cast(counter.QuadPart) * UINT64_C(1000000000) / static_cast(frequency.QuadPart); + } + +public: + CallSpot call_spot = SimulationStart; + LFXStats lfx_stats = {}; + bool fg = false; + bool active = true; + bool force_lfx = false; + + inline HRESULT init_al2(IUnknown *pDevice) { +#if _MSC_VER && _WIN64 + if (mode == AntiLag2 && !context_dx12.m_pAntiLagAPI && !context_dx11.m_pAntiLagAPI) { + ID3D12Device* device = nullptr; + HRESULT hr = pDevice->QueryInterface(__uuidof(ID3D12Device), reinterpret_cast(&device)); + HRESULT init_return = S_FALSE; + if (hr == S_OK) { + init_return = AMD::AntiLag2DX12::Initialize(&context_dx12, device); + } else { + init_return = AMD::AntiLag2DX11::Initialize(&context_dx11); + } + al_available = init_return == S_OK; + } +#else + al_available = false; +#endif + return 0x2137; + } + + void init_lfx() { + lf = new lfx::LatencyFleX(); + } + + inline HRESULT update() { + if (!active) return S_FALSE; + + if (al_available && !force_lfx && (min_interval_us == 0 || !fg)) + mode = AntiLag2; + else + mode = LatencyFlex; + + spdlog::debug("LowLatency algo: {}", mode == AntiLag2 ? "AntiLag 2" : "LatencyFlex"); + spdlog::debug("FG status: {}", fg ? "enabled" : "disabled"); + + if (mode == AntiLag2) { +#if _MSC_VER && _WIN64 + if (lfx_stats.frame_id != 1) lfx_stats.needs_reset = true; + int max_fps = min_interval_us > 0 ? 1000000 / min_interval_us : 0; + if (context_dx12.m_pAntiLagAPI) + return AMD::AntiLag2DX12::Update(&context_dx12, true, max_fps); + else if (context_dx11.m_pAntiLagAPI) + return AMD::AntiLag2DX11::Update(&context_dx11, true, max_fps); +#endif + } else if (mode == LatencyFlex) { + if (lfx_stats.needs_reset) { + spdlog::info("LFX Reset"); + lfx_stats.frame_id = 1; + lfx_stats.needs_reset = false; + lf->Reset(); + } + uint64_t current_timestamp = GetTimestamp(); + uint64_t timestamp; + + // Set FPS Limiter + lf->target_frame_time = 1000 * min_interval_us; + + lf->EndFrame(lfx_stats.frame_id, current_timestamp, &lfx_stats.latency, &lfx_stats.frame_time); + spdlog::debug("LFX latency: {}, frame_time: {}, current_timestamp: {}", lfx_stats.latency, lfx_stats.frame_time, current_timestamp); + lfx_stats.frame_id++; + lfx_stats.target = lf->GetWaitTarget(lfx_stats.frame_id); + + if (lfx_stats.target > current_timestamp) { + uint64_t extra_delay = 0; + // uint64_t extra_delay = (lfx_stats.target - current_timestamp) * 0.15; + static uint64_t timeout_events = 0; + uint64_t timeout_timestamp = current_timestamp + 50000000ULL; + if (lfx_stats.target > timeout_timestamp) { + timestamp = timeout_timestamp; + timeout_events++; + lfx_stats.needs_reset = timeout_events > 5; + } else { + timestamp = lfx_stats.target + extra_delay; + timeout_events = 0; + } + std::this_thread::sleep_for(std::chrono::nanoseconds(lfx_stats.target + extra_delay - current_timestamp)); + } else { + timestamp = current_timestamp; + } + + lf->BeginFrame(lfx_stats.frame_id, lfx_stats.target, timestamp); + return S_OK; + } + return S_FALSE; + } + + inline HRESULT set_fg_type(bool interpolated) { +#if _MSC_VER && _WIN64 + if (mode == AntiLag2) + return AMD::AntiLag2DX12::SetFrameGenFrameType(&context_dx12, interpolated); +#endif + return S_FALSE; + } + + inline HRESULT mark_end_of_rendering() { +#if _MSC_VER && _WIN64 + if (mode == AntiLag2) + return AMD::AntiLag2DX12::MarkEndOfFrameRendering(&context_dx12); +#endif + return S_FALSE; + } + + inline void unload() { +#if _MSC_VER && _WIN64 + if (context_dx12.m_pAntiLagAPI) AMD::AntiLag2DX12::DeInitialize(&context_dx12); + if (context_dx11.m_pAntiLagAPI) AMD::AntiLag2DX11::DeInitialize(&context_dx11); +#endif + } + + void set_min_interval_us(unsigned long interval_us) { + if (min_interval_us != interval_us) { + min_interval_us = interval_us; + spdlog::info("Changed max fps: {}", interval_us > 0 ? 1000000 / interval_us : 0); + } + } + + Mode get_mode() { + return mode; + } +}; \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/main.cpp b/OptiScaler/nvapi/fakenvapi/main.cpp index db14ae16..d28b3342 100755 --- a/OptiScaler/nvapi/fakenvapi/main.cpp +++ b/OptiScaler/nvapi/fakenvapi/main.cpp @@ -4,26 +4,31 @@ #include #include -#include "../include/nvapi_interface.h" +#include "../external/nvapi_interface.h" #if defined __MINGW64__ || defined __MINGW32__ #include "../include/d3d12.h" #else #include #endif -#include "../include/nvapi.h" -#include "nvapi.h" +#include "../external/nvapi.h" +#include "fakenvapi.h" #include "log.h" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - auto logEnv = std::getenv("NVAPI_LOG"); + auto logEnv = std::getenv("FAKENVAPI_LOG"); +#ifdef TESTING + bool force_log = true; +#else + bool force_log = false; +#endif switch (fdwReason) { case DLL_PROCESS_ATTACH: - if (logEnv && *logEnv == '1') - prepareLogging("nvapi-dummy.log"); + if ((logEnv && *logEnv == '1') || force_log) + prepareLogging(spdlog::level::trace); else - prepareLogging(std::nullopt); - log("--------------"); + prepareLogging(spdlog::level::off); + spdlog::critical("----------------"); break; case DLL_PROCESS_DETACH: closeLogging(); @@ -36,15 +41,17 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { NVAPI_INTERFACE_TABLE additional_interface_table[] = { { "NvAPI_Diag_ReportCallStart", 0x33c7358c }, { "NvAPI_Diag_ReportCallReturn", 0x593e8644 }, - { "MISC_unknown", 0xe9b009b9 }, - { "MISC_vulkan", 0x17d13d6 } + { "NvAPI_Unknown_1", 0xe9b009b9 }, + { "NvAPI_Vulkan_1", 0x17d13d6 }, + { "Dummy_GetLatency", 0x21372137 } }; namespace nvd { extern "C" { NvAPI_Status __cdecl placeholder() { // return Ok(); - return Error(NVAPI_NO_IMPLEMENTATION); + // return Error(NVAPI_NO_IMPLEMENTATION); + return NVAPI_NO_IMPLEMENTATION; // no logging } static std::unordered_map registry; @@ -67,7 +74,7 @@ namespace nvd { [id](const auto& item) { return item.id == id; }); if (it == std::end(extended_interface_table)) { - log(std::format("NvAPI_QueryInterface (0x{:x}): Unknown interface ID", id)); + spdlog::debug("NvAPI_QueryInterface (0x{:x}): Unknown interface ID", id); return registry.insert({ id, nullptr }).first->second; } @@ -107,6 +114,7 @@ namespace nvd { INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetSleepMode) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetLatencyMarker) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_Sleep) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D_SetReflexSync) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_IsNvShaderExtnOpCodeSupported) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_BeginUAVOverlap) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D11_EndUAVOverlap) @@ -120,14 +128,17 @@ namespace nvd { INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_D3D12_SetAsyncFrameMarker) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_CreateSession) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_LoadSettings) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SaveSettings) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetBaseProfile) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_GetSetting) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_SetSetting) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_DRS_DestroySession) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unknown_1) + INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Vulkan_1) INSERT_AND_RETURN_WHEN_EQUALS(NvAPI_Unload) - INSERT_AND_RETURN_WHEN_EQUALS(MISC_unknown) - INSERT_AND_RETURN_WHEN_EQUALS(MISC_vulkan) + INSERT_AND_RETURN_WHEN_EQUALS(Dummy_GetLatency) - log(std::format("{}: not implemented, placeholder given", it->func)); + spdlog::debug("{}: not implemented, placeholder given", it->func); return registry.insert({ id, (void*)placeholder }).first->second; // return registry.insert({ id, nullptr }).first->second; } diff --git a/OptiScaler/nvapi/fakenvapi/meson.build b/OptiScaler/nvapi/fakenvapi/meson.build index b7d2f9a7..bcddfa1b 100644 --- a/OptiScaler/nvapi/fakenvapi/meson.build +++ b/OptiScaler/nvapi/fakenvapi/meson.build @@ -1,7 +1,8 @@ dll = shared_library( 'nvapi'+target_suffix, - ['main.cpp', 'nvapi.cpp', 'spoofInfo.cpp', 'util.cpp', 'log.cpp'], + ['main.cpp', 'fakenvapi.cpp', 'util.cpp', 'log.cpp'], name_prefix : '', dependencies : [ lib_dxgi ], + include_directories: [ spdlog_headers ], install: true ) diff --git a/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp b/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp deleted file mode 100644 index a0cc6f55..00000000 --- a/OptiScaler/nvapi/fakenvapi/spoofInfo.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "spoofInfo.h" - -namespace spoof { - void driverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo) { - driverInfo->driverVersion = driverVersion; - tonvss(driverInfo->szBuildBranch, buildBranch); - driverInfo->bIsDCHDriver = isDCHDriver; - driverInfo->bIsNVIDIAStudioPackage = isNVIDIAStudioPackage; - driverInfo->bIsNVIDIARTXProductionBranchPackage = isNVIDIARTXProductionBranchPackage; - driverInfo->bIsNVIDIARTXNewFeatureBranchPackage = isNVIDIARTXNewFeatureBranchPackage; - if (driverInfo->version == 2) - tonvss(driverInfo->szBuildBaseBranch, buildBaseBranch); - } -} \ No newline at end of file diff --git a/OptiScaler/nvapi/fakenvapi/spoofInfo.h b/OptiScaler/nvapi/fakenvapi/spoofInfo.h deleted file mode 100644 index 23dace17..00000000 --- a/OptiScaler/nvapi/fakenvapi/spoofInfo.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include "util.h" - -namespace spoof { - constexpr NvU32 driverVersion = 99999; - constexpr auto buildBranch = "buildBranch"; - constexpr NvU32 isDCHDriver = 1; - constexpr NvU32 isNVIDIAStudioPackage = 1; - constexpr NvU32 isNVIDIARTXProductionBranchPackage = 1; - constexpr NvU32 isNVIDIARTXNewFeatureBranchPackage = 1; - constexpr auto buildBaseBranch = "buildBaseBranch"; - - constexpr auto fullGPUName = "NVIDIA GeForce RTX 4090"; - constexpr NV_GPU_ARCHITECTURE_ID arch = NV_GPU_ARCHITECTURE_AD100; - constexpr NV_GPU_ARCH_IMPLEMENTATION_ID implementation = NV_GPU_ARCH_IMPLEMENTATION_AD102; - constexpr NV_GPU_CHIP_REVISION revision = NV_GPU_CHIP_REV_UNKNOWN; - - void driverInfo(NV_DISPLAY_DRIVER_INFO* driverInfo); -} diff --git a/OptiScaler/nvapi/fakenvapi/util.h b/OptiScaler/nvapi/fakenvapi/util.h old mode 100644 new mode 100755 index 3f4153ca..92751f70 --- a/OptiScaler/nvapi/fakenvapi/util.h +++ b/OptiScaler/nvapi/fakenvapi/util.h @@ -1,5 +1,5 @@ #pragma once -#include "../include/nvapi.h" +#include "../external/nvapi.h" #include #include #include