Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Reflex FPS framerate limit slider #108

Merged
merged 8 commits into from
Nov 7, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add an fps cap slider
FakeMichau committed Oct 26, 2024

Verified

This commit was signed with the committer’s verified signature.
aljo242 Alex | Interchain Labs
commit 8c38d2751c7f47d6b07537cba4ca794d62c9e232
10 changes: 10 additions & 0 deletions OptiScaler/Config.cpp
Original file line number Diff line number Diff line change
@@ -59,6 +59,11 @@ bool Config::Reload(std::filesystem::path iniPath)
FGHUDFixExtended = readBool("FrameGen", "HUDFixExtended");
}

// Reflex
{
FramerateLimit = readFloat("Reflex", "FramerateLimit");
}

// FSR
{
FsrVerticalFov = readFloat("FSR", "VerticalFov");
@@ -482,6 +487,11 @@ bool Config::SaveIni()
ini.SetValue("FrameGen", "HUDFixExtended", GetBoolValue(Instance()->FGHUDFixExtended).c_str());
}

// Reflex
{
ini.SetValue("Reflex", "FramerateLimit", GetFloatValue(Instance()->FramerateLimit).c_str());
}

// Output Scaling
{
ini.SetValue("OutputScaling", "Enabled", GetBoolValue(Instance()->OutputScalingEnabled).c_str());
4 changes: 4 additions & 0 deletions OptiScaler/Config.h
Original file line number Diff line number Diff line change
@@ -204,6 +204,10 @@ class Config
std::optional<uint32_t> FN_LatencyFlexMode; // conservative - aggressive - reflex ids
std::optional<uint32_t> FN_ForceReflex; // in-game - force disable - force enable

// reflex
bool ReflexAvailable = false;
std::optional<float> FramerateLimit;

// for realtime changes
bool changeBackend = false;
std::string newBackend = "";
104 changes: 5 additions & 99 deletions OptiScaler/NVNGX_Proxy.h
Original file line number Diff line number Diff line change
@@ -6,8 +6,7 @@
#include "Logger.h"
#include <vulkan/vulkan.hpp>

#include "nvapi/nvapi.h"
#include "fakenvapi.h"
#include "nvapi/NvApiHooks.h"

#include <filesystem>
#include "detours/detours.h"
@@ -17,82 +16,14 @@ constexpr unsigned long long app_id_override = 0x24480451;

#pragma region spoofing hooks for 16xx

// NvAPI_GPU_GetArchInfo hooking based on Nukem's spoofing code here
// https://github.com/Nukem9/dlssg-to-fsr3/blob/89ddc8c1cce4593fb420e633a06605c3c4b9c3cf/source/wrapper_generic/nvapi.cpp#L50

enum class NV_INTERFACE : uint32_t
{
GPU_GetArchInfo = 0xD8265D24,
D3D12_SetRawScgPriority = 0x5DB3048A,
};

typedef void* (__stdcall* PFN_NvApi_QueryInterface)(NV_INTERFACE InterfaceId);
typedef NVSDK_NGX_Result(*PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements)(IDXGIAdapter* Adapter, const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported);
typedef NVSDK_NGX_Result(*PFN_NVSDK_NGX_VULKAN_GetFeatureRequirements)(const VkInstance Instance, const VkPhysicalDevice PhysicalDevice,
const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported);

using PfnNvAPI_GPU_GetArchInfo = uint32_t(__stdcall*)(void* GPUHandle, NV_GPU_ARCH_INFO* ArchInfo);

inline static PFN_NvApi_QueryInterface OriginalNvAPI_QueryInterface = nullptr;
inline static PfnNvAPI_GPU_GetArchInfo OriginalNvAPI_GPU_GetArchInfo = nullptr;
inline static PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements Original_D3D11_GetFeatureRequirements = nullptr;
inline static PFN_NVSDK_NGX_D3D1X_GetFeatureRequirements Original_D3D12_GetFeatureRequirements = nullptr;
inline static PFN_NVSDK_NGX_VULKAN_GetFeatureRequirements Original_Vulkan_GetFeatureRequirements = nullptr;

inline static uint32_t __stdcall HookedNvAPI_GPU_GetArchInfo(void* GPUHandle, NV_GPU_ARCH_INFO* ArchInfo)
{
if (OriginalNvAPI_GPU_GetArchInfo)
{
const auto status = OriginalNvAPI_GPU_GetArchInfo(GPUHandle, ArchInfo);

if (status == 0 && ArchInfo)
{
LOG_DEBUG("From api arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision);

// for 16xx cards
if (ArchInfo->architecture == NV_GPU_ARCHITECTURE_TU100 && ArchInfo->implementation > NV_GPU_ARCH_IMPLEMENTATION_TU106)
{
ArchInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_TU106;
ArchInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_TU106;

LOG_INFO("Spoofed arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision);
}
//else if (ArchInfo->architecture < NV_GPU_ARCHITECTURE_TU100 && ArchInfo->architecture >= NV_GPU_ARCHITECTURE_GP100)
//{
// LOG_INFO("Spoofing below 16xx arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision);

// ArchInfo->architecture = NV_GPU_ARCHITECTURE_TU100;
// ArchInfo->architecture_id = NV_GPU_ARCHITECTURE_TU100;
// ArchInfo->implementation = NV_GPU_ARCH_IMPLEMENTATION_TU106;
// ArchInfo->implementation_id = NV_GPU_ARCH_IMPLEMENTATION_TU106;

// LOG_INFO("Spoofed arch: {0:X} impl: {1:X} rev: {2:X}!", ArchInfo->architecture, ArchInfo->implementation, ArchInfo->revision);
//}
}

return status;
}

return 0xFFFFFFFF;
}

inline static void* __stdcall HookedNvAPI_QueryInterface(NV_INTERFACE InterfaceId)
{
LOG_FUNC();
const auto result = OriginalNvAPI_QueryInterface(InterfaceId);

if (result)
{
if (InterfaceId == NV_INTERFACE::GPU_GetArchInfo && !Config::Instance()->DE_Available)
{
OriginalNvAPI_GPU_GetArchInfo = static_cast<PfnNvAPI_GPU_GetArchInfo>(result);
return &HookedNvAPI_GPU_GetArchInfo;
}
}

return result;
}

inline static NVSDK_NGX_Result __stdcall Hooked_Dx12_GetFeatureRequirements(IDXGIAdapter* Adapter, const NVSDK_NGX_FeatureDiscoveryInfo* FeatureDiscoveryInfo, NVSDK_NGX_FeatureRequirement* OutSupported)
{
LOG_FUNC();
@@ -145,27 +76,6 @@ inline static NVSDK_NGX_Result __stdcall Hooked_Vulkan_GetFeatureRequirements(co
return result;
}

inline static void HookNvApi()
{
if (OriginalNvAPI_QueryInterface != nullptr)
return;

LOG_DEBUG("Trying to hook NvApi");
OriginalNvAPI_QueryInterface = (PFN_NvApi_QueryInterface)DetourFindFunction("nvapi64.dll", "nvapi_QueryInterface");
LOG_DEBUG("OriginalNvAPI_QueryInterface = {0:X}", (unsigned long long)OriginalNvAPI_QueryInterface);

if (OriginalNvAPI_QueryInterface != nullptr)
{
LOG_INFO("NvAPI_QueryInterface found, hooking!");
fakenvapi::Init((fakenvapi::PFN_Fake_QueryInterface&)OriginalNvAPI_QueryInterface);

DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalNvAPI_QueryInterface, HookedNvAPI_QueryInterface);
DetourTransactionCommit();
}
}

inline static void HookNgxApi(HMODULE nvngx)
{
if (Original_D3D11_GetFeatureRequirements != nullptr || Original_D3D12_GetFeatureRequirements != nullptr)
@@ -199,17 +109,13 @@ inline static void HookNgxApi(HMODULE nvngx)

inline static void UnhookApis()
{
if (OriginalNvAPI_QueryInterface != nullptr || Original_D3D11_GetFeatureRequirements != nullptr || Original_D3D12_GetFeatureRequirements != nullptr)
NvApiHooks::Unhook();

if (Original_D3D11_GetFeatureRequirements != nullptr || Original_D3D12_GetFeatureRequirements != nullptr)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());

if (OriginalNvAPI_QueryInterface != nullptr)
{
DetourDetach(&(PVOID&)OriginalNvAPI_QueryInterface, HookedNvAPI_QueryInterface);
OriginalNvAPI_QueryInterface = nullptr;
}

if (Original_D3D11_GetFeatureRequirements != nullptr)
{
DetourDetach(&(PVOID&)Original_D3D11_GetFeatureRequirements, Hooked_Dx11_GetFeatureRequirements);
@@ -381,7 +287,7 @@ class NVNGXProxy
if (_dll != nullptr)
return;

HookNvApi();
NvApiHooks::Hook();

LOG_INFO("");

7 changes: 5 additions & 2 deletions OptiScaler/OptiScaler.vcxproj
Original file line number Diff line number Diff line change
@@ -207,7 +207,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
<ClInclude Include="bias\Bias_Dx12.h" />
<ClInclude Include="bias\Bias_Dx11.h" />
<ClInclude Include="bias\precompile\Bias_Shader.h" />
<ClInclude Include="fakenvapi.h" />
<ClInclude Include="nvapi\fakenvapi.h" />
<ClInclude Include="format_transfer\FT_Common.h" />
<ClInclude Include="format_transfer\FT_Dx12.h" />
<ClInclude Include="FfxApi_Proxy.h" />
@@ -216,12 +216,14 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
<ClInclude Include="format_transfer\precompile\R8G8B8A8_Shader.h" />
<ClInclude Include="hooks\HooksDx.h" />
<ClInclude Include="hooks\HooksVk.h" />
<ClInclude Include="nvapi\NvApiHooks.h" />
<ClInclude Include="nvapi\NvApiTypes.h" />
<ClInclude Include="output_scaling\OS_Common.h" />
<ClInclude Include="output_scaling\OS_Dx12.h" />
<ClInclude Include="output_scaling\precompile\BCDS_Shader.h" />
<ClInclude Include="output_scaling\precompile\BCUS_Shader.h" />
<ClInclude Include="bicubicscaling\precompile\FSR_Shader.h" />
<ClInclude Include="nvapi\nvapi.h" />
<ClInclude Include="nvapi\external\nvapi.h" />
<ClInclude Include="backends\fsr2_212\FSR2Feature_212.h" />
<ClInclude Include="backends\fsr2_212\FSR2Feature_Dx11On12_212.h" />
<ClInclude Include="backends\fsr2_212\FSR2Feature_Dx12_212.h" />
@@ -266,6 +268,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
<ClInclude Include="rcas\RCAS_Common.h" />
<ClInclude Include="rcas\RCAS_Dx11.h" />
<ClInclude Include="rcas\RCAS_Dx12.h" />
<ClInclude Include="nvapi\ReflexHooks.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Util.h" />
<ClInclude Include="backends\xess\XeSSFeature_Dx11.h" />
13 changes: 11 additions & 2 deletions OptiScaler/OptiScaler.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -134,7 +134,7 @@
<ClInclude Include="backends\dlss\DLSSFeature_Dx11.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nvapi\nvapi.h">
<ClInclude Include="nvapi\external\nvapi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="backends\dlss\DLSSFeature_Vk.h">
@@ -269,7 +269,16 @@
<ClInclude Include="XeSS_Proxy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="fakenvapi.h">
<ClInclude Include="nvapi\fakenvapi.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nvapi\ReflexHooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nvapi\NvApiHooks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nvapi\NvApiTypes.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
2 changes: 1 addition & 1 deletion OptiScaler/backends/dlss/DLSSFeature.cpp
Original file line number Diff line number Diff line change
@@ -353,7 +353,7 @@ DLSSFeature::DLSSFeature(unsigned int handleId, NVSDK_NGX_Parameter* InParameter

if (NVNGXProxy::NVNGXModule() != nullptr && !Config::Instance()->DE_Available)
{
HookNvApi();
NvApiHooks::Hook();
HookNgxApi(NVNGXProxy::NVNGXModule());
}

2 changes: 2 additions & 0 deletions OptiScaler/hooks/HooksDx.cpp
Original file line number Diff line number Diff line change
@@ -1580,6 +1580,8 @@ static HRESULT Present(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags
if (Config::Instance()->CurrentFeature != nullptr)
fgPresentedFrame = Config::Instance()->CurrentFeature->FrameCount();

ReflexHooks::update(FrameGen_Dx12::fgIsActive);

// release used objects
if (cq != nullptr)
cq->Release();
3 changes: 2 additions & 1 deletion OptiScaler/hooks/HooksDx.h
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@
#include <dxgi1_6.h>

#include "../FfxApi_Proxy.h"
#include "../NVNGX_Proxy.h"
#include "../nvapi/fakenvapi.h"
#include "../nvapi/ReflexHooks.h"
#include <dx12/ffx_api_dx12.h>
#include <ffx_framegeneration.h>

16 changes: 16 additions & 0 deletions OptiScaler/imgui/imgui_common.cpp
Original file line number Diff line number Diff line change
@@ -1398,6 +1398,22 @@ void ImGuiCommon::RenderMenu()
}
}

// Reflex ---------------------
if (!Config::Instance()->DE_Available && Config::Instance()->ReflexAvailable)
{
ImGui::SeparatorText("Reflex");

// set inital value
if (Config::Instance()->FramerateLimit.has_value() && _limitFps > 200)
_limitFps = Config::Instance()->FramerateLimit.value();

ImGui::SliderFloat("FPS Limit", &_limitFps, 0, 200, "%.0f");

if (ImGui::Button("Apply Limit")) {
Config::Instance()->FramerateLimit = _limitFps;
}
}

// OUTPUT SCALING -----------------------------
if (Config::Instance()->Api == NVNGX_DX12 || Config::Instance()->Api == NVNGX_DX11)
{
3 changes: 3 additions & 0 deletions OptiScaler/imgui/imgui_common.h
Original file line number Diff line number Diff line change
@@ -34,6 +34,9 @@ class ImGuiCommon
// dlss enabler
inline static int _deLimitFps = 500;

// reflex
inline static float _limitFps = 500;

// fsr3x
inline static int _fsr3xIndex = -1;

Loading