diff --git a/OptiScaler/DllNames.h b/OptiScaler/DllNames.h index a36d59fd..3dceb649 100644 --- a/OptiScaler/DllNames.h +++ b/OptiScaler/DllNames.h @@ -145,6 +145,7 @@ DEFINE_NAME_VECTORS(ffxDx12FG, "amd_fidelityfx_framegeneration_dx12"); DEFINE_NAME_VECTORS(ffxDx12Denoiser, "amd_fidelityfx_denoiser_dx12"); DEFINE_NAME_VECTORS(ffxDx12Radiance, "amd_fidelityfx_radiancecache_dx12"); DEFINE_NAME_VECTORS(ffxVk, "amd_fidelityfx_vk"); +DEFINE_NAME_VECTORS(uell, "main"); inline static bool CompareFileName(std::string* first, std::string* second) { diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj index 6ca7094f..04f84167 100644 --- a/OptiScaler/OptiScaler.vcxproj +++ b/OptiScaler/OptiScaler.vcxproj @@ -399,6 +399,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + @@ -623,6 +624,7 @@ copy NUL "$(SolutionDir)x64\Release\a\!! EXTRACT ALL FILES TO GAME FOLDER !!" /Y + diff --git a/OptiScaler/OptiScaler.vcxproj.filters b/OptiScaler/OptiScaler.vcxproj.filters index ad0847db..6941a506 100644 --- a/OptiScaler/OptiScaler.vcxproj.filters +++ b/OptiScaler/OptiScaler.vcxproj.filters @@ -845,6 +845,18 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -1316,6 +1328,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/OptiScaler/State.h b/OptiScaler/State.h index 7289c9f7..cf663bce 100644 --- a/OptiScaler/State.h +++ b/OptiScaler/State.h @@ -169,6 +169,7 @@ class State bool reflexShowWarning = false; bool rtssReflexInjection = false; bool fakenvapiReloadLowLatency = false; + bool usingUeLL = false; UINT64 reflexFrameId = 0; UINT64 frameCount = 0; diff --git a/OptiScaler/hooks/LibraryLoad_Hooks.cpp b/OptiScaler/hooks/LibraryLoad_Hooks.cpp index f8088319..64163e16 100644 --- a/OptiScaler/hooks/LibraryLoad_Hooks.cpp +++ b/OptiScaler/hooks/LibraryLoad_Hooks.cpp @@ -30,6 +30,7 @@ #include #include +#include // #define LOG_LIB_OPERATIONS @@ -524,6 +525,28 @@ HMODULE LibraryLoadHooks::LoadLibraryCheckW(std::wstring libName, LPCWSTR lpLibF return module; } + // UeLL + // This will try to hook all UE4SS dll mods but only our one should be exporting those functions + if (CheckDllNameW(&libName, &uellNamesW)) + { + LOG_INFO("{} call!", libNameA); + + auto module = NtdllProxy::LoadLibraryExW_Ldr(libName.c_str(), NULL, NULL); + + auto setTickStartCallback = + (PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickStartCallback"); + auto setTickEndCallback = + (PFN_setTickCallback) KernelBaseProxy::GetProcAddress_()(module, "setTickEndCallback"); + + if (setTickStartCallback) + setTickStartCallback(UeLowLatency::tickStart); + + if (setTickEndCallback) + setTickEndCallback(UeLowLatency::tickEnd); + + return module; + } + CheckModulesInMemory(); return nullptr; diff --git a/OptiScaler/hooks/Reflex_Hooks.cpp b/OptiScaler/hooks/Reflex_Hooks.cpp index f5f4819e..7ae7dbe7 100644 --- a/OptiScaler/hooks/Reflex_Hooks.cpp +++ b/OptiScaler/hooks/Reflex_Hooks.cpp @@ -33,6 +33,13 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetSleepMode(IUnknown* pDev, NV_SET_SLEEP_ if (_minimumIntervalUs != 0) pSetSleepModeParams->minimumIntervalUs = _minimumIntervalUs; + if (State::Instance().usingUeLL) + { + pSetSleepModeParams->minimumIntervalUs = 0; + pSetSleepModeParams->bLowLatencyMode = false; + pSetSleepModeParams->bLowLatencyBoost = false; + } + if (State::Instance().activeFgOutput == FGOutput::XeFG) return nvapi_calls::NvAPI_D3D_SetSleepMode(pDev, pSetSleepModeParams); @@ -45,6 +52,11 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_Sleep(IUnknown* pDev) LOG_FUNC(); #endif + if (State::Instance().usingUeLL) + { + return NVAPI_OK; + } + static bool skip = false; if ((State::Instance().activeFgOutput == FGOutput::DLSSG || State::Instance().activeFgOutput == FGOutput::DLSSGWithNvngx) && @@ -64,7 +76,7 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_Sleep(IUnknown* pDev) StreamlineProxy::ReflexSleep()(*frameToken); skip = false; - return NvAPI_Status::NVAPI_OK; + return NVAPI_OK; } else { @@ -86,6 +98,11 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESU LOG_FUNC(); #endif + if (State::Instance().usingUeLL) + { + return NVAPI_OK; + } + if (State::Instance().activeFgOutput == FGOutput::XeFG) return nvapi_calls::NvAPI_D3D_GetLatency(pDev, pGetLatencyParams); @@ -120,6 +137,11 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetLatencyMarker(IUnknown* pDev, _lastFrameId[pSetLatencyMarkerParams->markerType] = pSetLatencyMarkerParams->frameID; _lastDev[pSetLatencyMarkerParams->markerType] = pDev; + if (State::Instance().usingUeLL) + { + return NVAPI_OK; + } + static bool skip[20] = {}; if (pSetLatencyMarkerParams->markerType == SIMULATION_START) @@ -297,6 +319,11 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* _lastAsyncMarkerFrameId = pSetAsyncFrameMarkerParams->frameID; + if (State::Instance().usingUeLL) + { + return NVAPI_OK; + } + if (pSetAsyncFrameMarkerParams->markerType == OUT_OF_BAND_PRESENT_START && State::Instance().streamlineVersion.major < 2) { diff --git a/OptiScaler/hooks/Reflex_Hooks.h b/OptiScaler/hooks/Reflex_Hooks.h index 5cf954e7..0c8e1192 100644 --- a/OptiScaler/hooks/Reflex_Hooks.h +++ b/OptiScaler/hooks/Reflex_Hooks.h @@ -90,5 +90,5 @@ class ReflexHooks static void update(bool optiFg_FgState, bool isVulkan); // 0 - disables the fps cap - inline static void setFPSLimit(float fps); + static void setFPSLimit(float fps); }; diff --git a/OptiScaler/misc/UeLowLatency.cpp b/OptiScaler/misc/UeLowLatency.cpp new file mode 100644 index 00000000..6fd3d7be --- /dev/null +++ b/OptiScaler/misc/UeLowLatency.cpp @@ -0,0 +1,73 @@ +#include "pch.h" +#include "UeLowLatency.h" +#include + +#include "nvapi/fakenvapi/low_latency_tech/ll_antilag2.h" +// #include "nvapi/fakenvapi/low_latency_tech/ll_xell.h" +#include "nvapi/fakenvapi/low_latency_tech/ll_latencyflex.h" + +void UeLowLatency::init() +{ + if (lowLatencyFeature) + return; + + lowLatencyFeature = new AntiLag2(); + + // lowLatencyFeature = new LatencyFlex(); + // Config::Instance()->FN_LatencyFlexMode.set_volatile_value(LFXMode::ReflexIDs); + + bool inited = false; + + if (auto dx11device = State::Instance().currentD3D11Device; dx11device) + { + inited = lowLatencyFeature->init(dx11device); + } + + if (auto dx12device = State::Instance().currentD3D12Device; !inited && dx12device) + { + inited = lowLatencyFeature->init(dx12device); + } + + State::Instance().usingUeLL = inited; + + if (inited) + { + LOG_DEBUG("Inited UeLowLatency"); + + SleepMode mode {}; + mode.low_latency_enabled = true; + lowLatencyFeature->set_sleep_mode(&mode); + + ReflexHooks::setFPSLimit(0); + } + else + { + delete lowLatencyFeature; + lowLatencyFeature = nullptr; + } +} + +void UeLowLatency::tickStart(int64_t frameId, float DeltaSeconds, bool bIdleMode) +{ + LOG_FUNC(); + + if (!lowLatencyFeature) + UeLowLatency::init(); + + lowLatencyFeature->sleep(); + + MarkerParams marker {}; + marker.marker_type = MarkerType::SIMULATION_START; + marker.frame_id = frameId; + lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, &marker); +} + +void UeLowLatency::tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleMode) +{ + LOG_FUNC(); + + MarkerParams marker {}; + marker.marker_type = MarkerType::SIMULATION_END; + marker.frame_id = frameId; + lowLatencyFeature->set_marker(State::Instance().currentD3D12Device, &marker); +} diff --git a/OptiScaler/misc/UeLowLatency.h b/OptiScaler/misc/UeLowLatency.h new file mode 100644 index 00000000..c82a125d --- /dev/null +++ b/OptiScaler/misc/UeLowLatency.h @@ -0,0 +1,16 @@ +#pragma once + +#include "nvapi/fakenvapi/low_latency_tech/low_latency_tech.h" + +typedef void (*PFN_FLTickExternal)(int64_t frameId, float DeltaSeconds, bool bIdleMode); +typedef void (*PFN_setTickCallback)(PFN_FLTickExternal callback); + +class UeLowLatency +{ + inline static LowLatencyTech* lowLatencyFeature = nullptr; + + public: + static void init(); + static void tickEnd(int64_t frameId, float DeltaSeconds, bool bIdleMode); + static void tickStart(int64_t frameId, float DeltaSeconds, bool bIdleMode); +};