diff --git a/OptiScaler/framegen/Streamline_Inputs_Dx12.cpp b/OptiScaler/framegen/Streamline_Inputs_Dx12.cpp index b7f35f41..795fa69a 100644 --- a/OptiScaler/framegen/Streamline_Inputs_Dx12.cpp +++ b/OptiScaler/framegen/Streamline_Inputs_Dx12.cpp @@ -127,7 +127,7 @@ bool Sl_Inputs_Dx12::evaluateState(ID3D12Device* device) bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCommandList* cmdBuffer, uint32_t frameId) { if (!cmdBuffer) - LOG_ERROR("cmdBuffer is null"); + LOG_TRACE("cmdBuffer is null"); auto fgOutput = reinterpret_cast(State::Instance().currentFG); @@ -166,15 +166,18 @@ bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCo auto hudlessResource = (ID3D12Resource*) tag.resource->native; const auto validity = - (tag.lifecycle == sl::eOnlyValidNow) ? FG_ResourceValidity::ValidNow : FG_ResourceValidity::UntilPresent; - fgOutput->SetResource(FG_ResourceType::HudlessColor, cmdBuffer, hudlessResource, tag.resource->width, - tag.resource->height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + (tag.lifecycle != sl::eOnlyValidNow) ? FG_ResourceValidity::UntilPresent : FG_ResourceValidity::ValidNow; + fgOutput->SetResource(FG_ResourceType::HudlessColor, cmdBuffer, hudlessResource, tag.extent.width, + tag.extent.height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + + // Assume hudless is the size used for interpolation + interpolationWidth = tag.extent.width; + interpolationHeight = tag.extent.height; auto static lastFormat = DXGI_FORMAT_UNKNOWN; auto format = hudlessResource->GetDesc().Format; // This might be specific to FSR FG - // Hopefully we don't need to use ffxCreateContextDescFrameGenerationHudless if (lastFormat != DXGI_FORMAT_UNKNOWN && lastFormat != format) { State::Instance().FGchanged = true; @@ -193,9 +196,9 @@ bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCo auto depthResource = (ID3D12Resource*) tag.resource->native; const auto validity = - (tag.lifecycle == sl::eOnlyValidNow) ? FG_ResourceValidity::ValidNow : FG_ResourceValidity::UntilPresent; - fgOutput->SetResource(FG_ResourceType::Depth, cmdBuffer, depthResource, tag.resource->width, - tag.resource->height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + (tag.lifecycle != sl::eOnlyValidNow) ? FG_ResourceValidity::UntilPresent : FG_ResourceValidity::ValidNow; + fgOutput->SetResource(FG_ResourceType::Depth, cmdBuffer, depthResource, tag.extent.width, tag.extent.height, + (D3D12_RESOURCE_STATES) tag.resource->state, validity); } else if (tag.type == sl::kBufferTypeMotionVectors) { @@ -208,9 +211,9 @@ bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCo auto mvResource = (ID3D12Resource*) tag.resource->native; const auto validity = - (tag.lifecycle == sl::eOnlyValidNow) ? FG_ResourceValidity::ValidNow : FG_ResourceValidity::UntilPresent; - fgOutput->SetResource(FG_ResourceType::Velocity, cmdBuffer, mvResource, tag.resource->width, - tag.resource->height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + (tag.lifecycle != sl::eOnlyValidNow) ? FG_ResourceValidity::UntilPresent : FG_ResourceValidity::ValidNow; + fgOutput->SetResource(FG_ResourceType::Velocity, cmdBuffer, mvResource, tag.extent.width, tag.extent.height, + (D3D12_RESOURCE_STATES) tag.resource->state, validity); } else if (tag.type == sl::kBufferTypeUIColorAndAlpha) { @@ -224,10 +227,10 @@ bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCo auto uiResource = (ID3D12Resource*) tag.resource->native; - const auto validity = (tag.lifecycle == sl::eOnlyValidNow) ? FG_ResourceValidity::ValidNow - : FG_ResourceValidity::UntilPresent; - fgOutput->SetResource(FG_ResourceType::UIColor, cmdBuffer, uiResource, tag.resource->width, - tag.resource->height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + const auto validity = (tag.lifecycle != sl::eOnlyValidNow) ? FG_ResourceValidity::UntilPresent + : FG_ResourceValidity::ValidNow; + fgOutput->SetResource(FG_ResourceType::UIColor, cmdBuffer, uiResource, tag.extent.width, tag.extent.height, + (D3D12_RESOURCE_STATES) tag.resource->state, validity); } } else if (tag.type == sl::kBufferTypeBidirectionalDistortionField) @@ -241,9 +244,9 @@ bool Sl_Inputs_Dx12::reportResource(const sl::ResourceTag& tag, ID3D12GraphicsCo auto distortionFieldResource = (ID3D12Resource*) tag.resource->native; const auto validity = - (tag.lifecycle == sl::eOnlyValidNow) ? FG_ResourceValidity::ValidNow : FG_ResourceValidity::UntilPresent; - fgOutput->SetResource(FG_ResourceType::Distortion, cmdBuffer, distortionFieldResource, tag.resource->width, - tag.resource->height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); + (tag.lifecycle != sl::eOnlyValidNow) ? FG_ResourceValidity::UntilPresent : FG_ResourceValidity::ValidNow; + fgOutput->SetResource(FG_ResourceType::Distortion, cmdBuffer, distortionFieldResource, tag.extent.width, + tag.extent.height, (D3D12_RESOURCE_STATES) tag.resource->state, validity); } if (readyForDispatch()) @@ -363,6 +366,8 @@ bool Sl_Inputs_Dx12::dispatchFG(ID3D12GraphicsCommandList* cmdBuffer) fgOutput->SetReset(slConstsRef.reset == sl::Boolean::eTrue); + fgOutput->SetInterpolationRect(interpolationWidth, interpolationHeight); + return true; } diff --git a/OptiScaler/framegen/Streamline_Inputs_Dx12.h b/OptiScaler/framegen/Streamline_Inputs_Dx12.h index 0d69a4a6..6a8be72d 100644 --- a/OptiScaler/framegen/Streamline_Inputs_Dx12.h +++ b/OptiScaler/framegen/Streamline_Inputs_Dx12.h @@ -25,6 +25,9 @@ class Sl_Inputs_Dx12 bool frameBasedTracking = false; uint32_t indexToFrameIdMapping[BUFFER_COUNT] {}; + uint32_t interpolationWidth = 0; + uint32_t interpolationHeight = 0; + std::optional* getFrameData(IFGFeature_Dx12* fgOutput); public: diff --git a/OptiScaler/hooks/HooksDx.cpp b/OptiScaler/hooks/HooksDx.cpp index b5a80c0d..c2fc34ec 100644 --- a/OptiScaler/hooks/HooksDx.cpp +++ b/OptiScaler/hooks/HooksDx.cpp @@ -268,8 +268,7 @@ static HRESULT hkFGPresent(void* This, UINT SyncInterval, UINT Flags) LOG_TRACE("Accuired FG->Mutex: {}", fg->Mutex.getOwner()); } - if (willPresent && State::Instance().currentCommandQueue != nullptr && - State::Instance().activeFgInput == FGInput::Upscaler && fg != nullptr && fg->IsActive()) + if (willPresent && State::Instance().currentCommandQueue != nullptr && fg != nullptr && fg->IsActive()) { fg->Present(); } diff --git a/OptiScaler/hooks/Streamline_Hooks.cpp b/OptiScaler/hooks/Streamline_Hooks.cpp index a2029ae9..6d1248cf 100644 --- a/OptiScaler/hooks/Streamline_Hooks.cpp +++ b/OptiScaler/hooks/Streamline_Hooks.cpp @@ -108,6 +108,12 @@ sl::Result StreamlineHooks::hkslInit(sl::Preferences* pref, uint64_t sdkVersion) renderApi = pref->renderAPI; State::Instance().slFGInputs.reportEngineType(pref->engine); + // bool hookSetTag = + // (State::Instance().activeFgInput == FGInput::Nukems || State::Instance().activeFgInput == FGInput::DLSSG); + + // if (hookSetTag) + // pref->flags &= ~(sl::PreferenceFlags::eAllowOTA | sl::PreferenceFlags::eLoadDownloadedPlugins); + return o_slInit(*pref, sdkVersion); } @@ -122,6 +128,12 @@ sl::Result StreamlineHooks::hkslSetTag(sl::ViewportHandle& viewport, sl::Resourc for (uint32_t i = 0; i < numTags; i++) { + if (tags[i].resource == nullptr) + { + LOG_TRACE("Resource of type: {} is null, continuing", tags[i].type); + continue; + } + // Cyberpunk hudless state fix for RDNA 2 if (State::Instance().gameQuirks & GameQuirk::CyberpunkHudlessStateOverride && tags[i].resource->state == @@ -158,6 +170,12 @@ sl::Result StreamlineHooks::hkslSetTagForFrame(const sl::FrameToken& frame, cons for (uint32_t i = 0; i < numResources; i++) { + if (resources[i].resource == nullptr) + { + LOG_TRACE("Resource of type: {} is null, continuing", resources[i].type); + continue; + } + if (State::Instance().activeFgInput == FGInput::DLSSG && (resources[i].type == sl::kBufferTypeHUDLessColor || resources[i].type == sl::kBufferTypeDepth || resources[i].type == sl::kBufferTypeHiResDepth || resources[i].type == sl::kBufferTypeLinearDepth || @@ -692,6 +710,8 @@ void StreamlineHooks::hookInterposer(HMODULE slInterposer) char dllPath[MAX_PATH]; GetModuleFileNameA(slInterposer, dllPath, MAX_PATH); + LOG_TRACE("slInterposer path: {}", dllPath); + Util::version_t sl_version; Util::GetDLLVersion(string_to_wstring(dllPath), &sl_version); @@ -727,8 +747,8 @@ void StreamlineHooks::hookInterposer(HMODULE slInterposer) DetourAttach(&(PVOID&) o_slInit, hkslInit); - bool hookSetTag = (Config::Instance()->FGInput.value_or_default() == FGInput::Nukems || - Config::Instance()->FGInput.value_or_default() == FGInput::DLSSG); + bool hookSetTag = (State::Instance().activeFgInput == FGInput::Nukems || + State::Instance().activeFgInput == FGInput::DLSSG); if (o_slSetTag != nullptr && hookSetTag) DetourAttach(&(PVOID&) o_slSetTag, hkslSetTag); @@ -736,20 +756,20 @@ void StreamlineHooks::hookInterposer(HMODULE slInterposer) if (o_slSetTagForFrame != nullptr && hookSetTag) DetourAttach(&(PVOID&) o_slSetTagForFrame, hkslSetTagForFrame); - if (o_slEvaluateFeature != nullptr) - DetourAttach(&(PVOID&) o_slEvaluateFeature, hkslEvaluateFeature); - - if (o_slAllocateResources != nullptr) - DetourAttach(&(PVOID&) o_slAllocateResources, hkslAllocateResources); - - if (o_slSetConstants != nullptr) + if (o_slSetConstants != nullptr && hookSetTag) DetourAttach(&(PVOID&) o_slSetConstants, hkslSetConstants); - if (o_slGetNativeInterface != nullptr) - DetourAttach(&(PVOID&) o_slGetNativeInterface, hkslGetNativeInterface); + // if (o_slEvaluateFeature != nullptr) + // DetourAttach(&(PVOID&) o_slEvaluateFeature, hkslEvaluateFeature); - if (o_slSetD3DDevice != nullptr) - DetourAttach(&(PVOID&) o_slSetD3DDevice, hkslSetD3DDevice); + // if (o_slAllocateResources != nullptr) + // DetourAttach(&(PVOID&) o_slAllocateResources, hkslAllocateResources); + + // if (o_slGetNativeInterface != nullptr) + // DetourAttach(&(PVOID&) o_slGetNativeInterface, hkslGetNativeInterface); + + // if (o_slSetD3DDevice != nullptr) + // DetourAttach(&(PVOID&) o_slSetD3DDevice, hkslSetD3DDevice); DetourTransactionCommit(); } diff --git a/OptiScaler/nvapi/ReflexHooks.cpp b/OptiScaler/nvapi/ReflexHooks.cpp index bb19da68..55840e64 100644 --- a/OptiScaler/nvapi/ReflexHooks.cpp +++ b/OptiScaler/nvapi/ReflexHooks.cpp @@ -18,7 +18,10 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetSleepMode(IUnknown* pDev, NV_SET_SLEEP_ if (_minimumIntervalUs != 0) pSetSleepModeParams->minimumIntervalUs = _minimumIntervalUs; - return o_NvAPI_D3D_SetSleepMode(pDev, pSetSleepModeParams); + if (State::Instance().activeFgOutput == FGOutput::XeFG && fakenvapi::ForNvidia_SetSleepMode) + return fakenvapi::ForNvidia_SetSleepMode(pDev, pSetSleepModeParams); + else + return o_NvAPI_D3D_SetSleepMode(pDev, pSetSleepModeParams); } NvAPI_Status ReflexHooks::hkNvAPI_D3D_Sleep(IUnknown* pDev) @@ -27,7 +30,10 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_Sleep(IUnknown* pDev) LOG_FUNC(); #endif - return o_NvAPI_D3D_Sleep(pDev); + if (State::Instance().activeFgOutput == FGOutput::XeFG && fakenvapi::ForNvidia_Sleep) + return fakenvapi::ForNvidia_Sleep(pDev); + else + return o_NvAPI_D3D_Sleep(pDev); } NvAPI_Status ReflexHooks::hkNvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESULT_PARAMS* pGetLatencyParams) @@ -36,7 +42,10 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_GetLatency(IUnknown* pDev, NV_LATENCY_RESU LOG_FUNC(); #endif - return o_NvAPI_D3D_GetLatency(pDev, pGetLatencyParams); + if (State::Instance().activeFgOutput == FGOutput::XeFG && fakenvapi::ForNvidia_GetLatency) + return fakenvapi::ForNvidia_GetLatency(pDev, pGetLatencyParams); + else + return o_NvAPI_D3D_GetLatency(pDev, pGetLatencyParams); } NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetLatencyMarker(IUnknown* pDev, @@ -75,7 +84,10 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D_SetLatencyMarker(IUnknown* pDev, State::Instance().slFGInputs.evaluateState(device12); } - return o_NvAPI_D3D_SetLatencyMarker(pDev, pSetLatencyMarkerParams); + if (State::Instance().activeFgOutput == FGOutput::XeFG && fakenvapi::ForNvidia_SetLatencyMarker) + return fakenvapi::ForNvidia_SetLatencyMarker(pDev, pSetLatencyMarkerParams); + else + return o_NvAPI_D3D_SetLatencyMarker(pDev, pSetLatencyMarkerParams); } NvAPI_Status ReflexHooks::hkNvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* pCommandQueue, @@ -119,7 +131,10 @@ NvAPI_Status ReflexHooks::hkNvAPI_D3D12_SetAsyncFrameMarker(ID3D12CommandQueue* } } - return o_NvAPI_D3D12_SetAsyncFrameMarker(pCommandQueue, pSetAsyncFrameMarkerParams); + if (State::Instance().activeFgOutput == FGOutput::XeFG && fakenvapi::ForNvidia_SetAsyncFrameMarker) + return fakenvapi::ForNvidia_SetAsyncFrameMarker(pCommandQueue, pSetAsyncFrameMarkerParams); + else + return o_NvAPI_D3D12_SetAsyncFrameMarker(pCommandQueue, pSetAsyncFrameMarkerParams); } NvAPI_Status ReflexHooks::hkNvAPI_Vulkan_SetLatencyMarker(HANDLE vkDevice, @@ -240,8 +255,9 @@ void ReflexHooks::update(bool optiFg_FgState, bool isVulkan) // Don't use when: Real Reflex markers + OptiFG + Reflex disabled, causes huge input latency State::Instance().reflexLimitsFps = fakenvapi::isUsingFakenvapi() || !optiFg_FgState || _lastSleepParams.bLowLatencyMode; - State::Instance().reflexShowWarning = - !fakenvapi::isUsingFakenvapi() && optiFg_FgState && _lastSleepParams.bLowLatencyMode; + State::Instance().reflexShowWarning = State::Instance().activeFgOutput != FGOutput::XeFG && + !fakenvapi::isUsingFakenvapi() && optiFg_FgState && + _lastSleepParams.bLowLatencyMode; } static float lastFps = 0; diff --git a/OptiScaler/nvapi/fakenvapi.cpp b/OptiScaler/nvapi/fakenvapi.cpp index 2d1fb425..9f2d4b29 100644 --- a/OptiScaler/nvapi/fakenvapi.cpp +++ b/OptiScaler/nvapi/fakenvapi.cpp @@ -1,9 +1,6 @@ #include "fakenvapi.h" #include "proxies/FfxApi_Proxy.h" -void* fakenvapi::_lowLatencyContext = nullptr; -Mode fakenvapi::_lowLatencyMode = Mode::LatencyFlex; - void fakenvapi::Init(PFN_NvApi_QueryInterface& queryInterface) { if (_inited) @@ -84,7 +81,10 @@ void fakenvapi::reportFGPresent(IDXGISwapChain* pSwapChain, bool fg_state, bool bool fakenvapi::updateModeAndContext() { - if (!isUsingFakenvapi()) + if (!isUsingFakenvapi() && State::Instance().activeFgOutput == FGOutput::XeFG) + auto loaded = fakenvapi::loadForNvidia(); + + if (!isUsingFakenvapi() && !isUsingFakenvapiOnNvidia()) return false; LOG_FUNC(); @@ -120,7 +120,10 @@ bool fakenvapi::updateModeAndContext() bool fakenvapi::setModeAndContext(void* context, Mode mode) { - if (!isUsingFakenvapi()) + if (!isUsingFakenvapi() && State::Instance().activeFgOutput == FGOutput::XeFG) + auto loaded = fakenvapi::loadForNvidia(); + + if (!isUsingFakenvapi() && !isUsingFakenvapiOnNvidia()) return false; LOG_FUNC(); @@ -138,8 +141,54 @@ bool fakenvapi::setModeAndContext(void* context, Mode mode) return false; } +bool fakenvapi::loadForNvidia() +{ + if (!State::Instance().isRunningOnNvidia) + return false; + + if (_dllForNvidia != nullptr) + return true; + + _dllForNvidia = KernelBaseProxy::LoadLibraryExW_()(L"fakenvapi.dll", NULL, 0); + + if (!_dllForNvidia) + return false; + + auto queryInterface = + (PFN_NvApi_QueryInterface) KernelBaseProxy::GetProcAddress_()(_dllForNvidia, "nvapi_QueryInterface"); + + if (queryInterface == nullptr) + { + _dllForNvidia = nullptr; + return false; + } + + ForNvidia_SetSleepMode = GET_INTERFACE(NvAPI_D3D_SetSleepMode, queryInterface); + ForNvidia_Sleep = GET_INTERFACE(NvAPI_D3D_Sleep, queryInterface); + ForNvidia_GetLatency = GET_INTERFACE(NvAPI_D3D_GetLatency, queryInterface); + ForNvidia_SetLatencyMarker = GET_INTERFACE(NvAPI_D3D_SetLatencyMarker, queryInterface); + ForNvidia_SetAsyncFrameMarker = GET_INTERFACE(NvAPI_D3D12_SetAsyncFrameMarker, queryInterface); + + Fake_InformFGState = static_cast(queryInterface(GET_ID(Fake_InformFGState))); + Fake_InformPresentFG = static_cast(queryInterface(GET_ID(Fake_InformPresentFG))); + Fake_GetAntiLagCtx = static_cast(queryInterface(GET_ID(Fake_GetAntiLagCtx))); + Fake_GetLowLatencyCtx = static_cast(queryInterface(GET_ID(Fake_GetLowLatencyCtx))); + Fake_SetLowLatencyCtx = static_cast(queryInterface(GET_ID(Fake_SetLowLatencyCtx))); + + if (Fake_SetLowLatencyCtx) + { + _initedForNvidia = true; + LOG_INFO("fakenvapi initialized for Nvidia"); + return true; + } + + LOG_INFO("Failed to initialize fakenvapi for Nvidia"); + return false; +} + // updateModeAndContext needs to be called before that Mode fakenvapi::getCurrentMode() { return _lowLatencyMode; } -// won't work with older fakenvapi builds bool fakenvapi::isUsingFakenvapi() { return _inited; } + +bool fakenvapi::isUsingFakenvapiOnNvidia() { return _initedForNvidia; } diff --git a/OptiScaler/nvapi/fakenvapi.h b/OptiScaler/nvapi/fakenvapi.h index 19038da5..163ef19a 100644 --- a/OptiScaler/nvapi/fakenvapi.h +++ b/OptiScaler/nvapi/fakenvapi.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "NvApiTypes.h" @@ -19,18 +20,28 @@ class fakenvapi inline static decltype(&Fake_SetLowLatencyCtx) Fake_SetLowLatencyCtx = nullptr; inline static bool _inited = false; - static void* _lowLatencyContext; - static Mode _lowLatencyMode; + inline static bool _initedForNvidia = false; + inline static void* _lowLatencyContext = nullptr; + inline static Mode _lowLatencyMode = Mode::LatencyFlex; + inline static HMODULE _dllForNvidia = nullptr; public: inline static const GUID IID_IFfxAntiLag2Data = { 0x5083ae5b, 0x8070, 0x4fca, { 0x8e, 0xe5, 0x35, 0x82, 0xdd, 0x36, 0x7d, 0x13 } }; + inline static decltype(&NvAPI_D3D_SetSleepMode) ForNvidia_SetSleepMode = nullptr; + inline static decltype(&NvAPI_D3D_Sleep) ForNvidia_Sleep = nullptr; + inline static decltype(&NvAPI_D3D_GetLatency) ForNvidia_GetLatency = nullptr; + inline static decltype(&NvAPI_D3D_SetLatencyMarker) ForNvidia_SetLatencyMarker = nullptr; + inline static decltype(&NvAPI_D3D12_SetAsyncFrameMarker) ForNvidia_SetAsyncFrameMarker = nullptr; + static void Init(PFN_NvApi_QueryInterface& queryInterface); static void reportFGPresent(IDXGISwapChain* pSwapChain, bool fg_state, bool frame_interpolated); static bool updateModeAndContext(); static bool setModeAndContext(void* context, Mode mode); + static bool loadForNvidia(); static Mode getCurrentMode(); static bool isUsingFakenvapi(); + static bool isUsingFakenvapiOnNvidia(); };