Re-implement FPS Limiter

This commit is contained in:
esuo1198
2025-07-06 23:05:23 +09:00
parent 5c64ac6981
commit 3ce7123685
8 changed files with 14 additions and 149 deletions
+2 -2
View File
@@ -162,8 +162,8 @@ set(SOURCES
src/Windows/WindowsError.cpp
src/Windows/MinimumLatencyAudioClient.cpp
src/patches/amauth.cpp
# src/patches/dxgi.cpp
# src/patches/fpslimiter.cpp
src/patches/dxgi.cpp
src/patches/fpslimiter.cpp
src/patches/audio.cpp
src/patches/plugins.cpp
src/patches/scanner.cpp
+1 -1
View File
@@ -56,7 +56,7 @@ res = { x = 1920, y = 1080 }
windowed = false # if set to false, will automatically go Fullscreen
cursor = true # Fullscreen will automatically hide cursor
vsync = false # Enable this if you are using a 120fps screen (and use "Let Application Decide" in Nvidia panel)
# fpslimit = 0 # Temporarily disabled, limit to 120 fps in Nvidia panel instead!!!
fpslimit = true # Limit the game to 120fps
model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only)
# | rate <= 0: default 1280x720
# | rate > 0: current resolution * rate
+1 -1
View File
@@ -36,7 +36,7 @@ res = { x = 1920, y = 1080 }
windowed = false # if set to false, will automatically go Fullscreen
cursor = true # Fullscreen will automatically hide cursor
vsync = false # Enable this if you are using a 120fps screen (and use "Let Application Decide" in Nvidia panel)
# fpslimit = 0 # Temporarily disabled, limit to 120 fps in Nvidia panel instead!!!
fpslimit = true # Limit the game to 120fps
model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only)
# | rate <= 0: default 1280x720
# | rate > 0: current resolution * rate
+1
View File
@@ -68,6 +68,7 @@ struct graphicsConfig {
};
resConfig res;
bool vsync = false;
bool fpslimit = true;
float model_res_rate = 1.0f;
};
+1 -1
View File
@@ -277,7 +277,7 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) {
patches::Lua::Init ();
patches::Scanner::Init ();
patches::Audio::Init ();
// patches::Dxgi::Init ();
patches::Dxgi::Init ();
patches::AmAuth::Init ();
patches::Language::Init ();
patches::TestMode::Init ();
+4 -139
View File
@@ -2,18 +2,11 @@
#define D3D11_NO_HELPERS
#define INITGUID
#include "d3d11.h"
#include "d3d12.h"
#include "dxgi1_2.h"
#include "dxgi1_3.h"
#include "dxgi1_4.h"
#include "dxgi1_5.h"
#include "dxgi1_6.h"
#include "helpers.h"
#include "config.h"
#include "bnusio.h"
#include "patches.h"
#include <intrin.h>
/*
* Reference: https://github.com/teknogods/OpenParrot/blob/master/OpenParrot/src/Functions/WindowedDxgi.cpp
@@ -25,40 +18,15 @@ namespace patches::Dxgi {
static bool FpsLimiterEnable = false;
// Prototypes
static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChain) (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc,
IDXGISwapChain **ppSwapChain);
static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChainForHwnd) (IDXGIFactory2 *This, IUnknown *pDevice, HWND hWnd,
const DXGI_SWAP_CHAIN_DESC1 *pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc,
IDXGIOutput *pRestrictToOutput, IDXGISwapChain1 **ppSwapChain);
static HRESULT (STDMETHODCALLTYPE *g_oldPresentWrap) (IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags);
static HRESULT (STDMETHODCALLTYPE *g_oldPresent1Wrap) (IDXGISwapChain1 *pSwapChain, UINT SyncInterval, UINT Flags);
static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChain2) (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc,
IDXGISwapChain **ppSwapChain);
static HRESULT (WINAPI *g_origCreateDXGIFactory2) (UINT Flags, REFIID riid, void **ppFactory);
static HRESULT (WINAPI *g_origCreateDXGIFactory) (REFIID, void **);
static HRESULT (WINAPI *g_origD3D11CreateDeviceAndSwapChain) (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags,
const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion,
/*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain,
ID3D11Device **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext);
static HRESULT STDMETHODCALLTYPE CreateSwapChainWrap (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc,
IDXGISwapChain **ppSwapChain);
static HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndWrap (IDXGIFactory2 *This, IUnknown *pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput,
IDXGISwapChain1 **ppSwapChain);
static HRESULT STDMETHODCALLTYPE PresentWrap (IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE Present1Wrap (IDXGISwapChain1 *pSwapChain, UINT SyncInterval, UINT Flags);
static HRESULT STDMETHODCALLTYPE CreateSwapChain2Wrap (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc,
IDXGISwapChain **ppSwapChain);
static HRESULT WINAPI CreateDXGIFactory2Wrap (UINT Flags, REFIID riid, void **ppFactory);
static HRESULT WINAPI CreateDXGIFactoryWrap (REFIID riid, _COM_Outptr_ void **ppFactory);
static HRESULT WINAPI D3D11CreateDeviceAndSwapChainWrap (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags,
const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion,
/*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain,
ID3D11Device **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel,
ID3D11DeviceContext **ppImmediateContext);
// Functions
template <typename T>
@@ -72,35 +40,6 @@ HookVtableFunction (T *functionPtr, T target) {
return old;
}
static HRESULT STDMETHODCALLTYPE
CreateSwapChainWrap (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGISwapChain **ppSwapChain) {
const HRESULT hr = g_oldCreateSwapChain (This, pDevice, pDesc, ppSwapChain);
if (*ppSwapChain) {
if (FpsLimiterEnable) {
const auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, PresentWrap);
g_oldPresentWrap = old2 ? old2 : g_oldPresentWrap;
}
}
return hr;
}
static HRESULT STDMETHODCALLTYPE
CreateSwapChainForHwndWrap (IDXGIFactory2 *This, IUnknown *pDevice, const HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput, IDXGISwapChain1 **ppSwapChain) {
const HRESULT hr = g_oldCreateSwapChainForHwnd (This, pDevice, hWnd, pDesc, nullptr, pRestrictToOutput, ppSwapChain);
if (*ppSwapChain) {
if (FpsLimiterEnable) {
const auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, Present1Wrap);
g_oldPresent1Wrap = old2 ? old2 : g_oldPresent1Wrap;
}
}
return hr;
}
static HRESULT STDMETHODCALLTYPE
PresentWrap (IDXGISwapChain *pSwapChain, const UINT SyncInterval, const UINT Flags) {
if (FpsLimiterEnable) FpsLimiter::Update ();
@@ -110,15 +49,6 @@ PresentWrap (IDXGISwapChain *pSwapChain, const UINT SyncInterval, const UINT Fla
return g_oldPresentWrap (pSwapChain, SyncInterval, Flags);
}
static HRESULT STDMETHODCALLTYPE
Present1Wrap (IDXGISwapChain1 *pSwapChain, const UINT SyncInterval, const UINT Flags) {
if (FpsLimiterEnable) FpsLimiter::Update ();
bnusio::Update ();
return g_oldPresent1Wrap (pSwapChain, SyncInterval, Flags);
}
static HRESULT STDMETHODCALLTYPE
CreateSwapChain2Wrap (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGISwapChain **ppSwapChain) {
const HRESULT hr = g_oldCreateSwapChain2 (This, pDevice, pDesc, ppSwapChain);
@@ -147,82 +77,17 @@ CreateDXGIFactory2Wrap (const UINT Flags, REFIID riid, void **ppFactory) {
return hr;
}
static HRESULT WINAPI
CreateDXGIFactoryWrap (REFIID riid, _COM_Outptr_ void **ppFactory) {
const HRESULT hr = g_origCreateDXGIFactory (riid, ppFactory);
if (SUCCEEDED (hr)) {
int factoryType = 0;
if (IsEqualIID (riid, IID_IDXGIFactory1)) factoryType = 1;
else if (IsEqualIID (riid, IID_IDXGIFactory2)) factoryType = 2;
else if (IsEqualIID (riid, IID_IDXGIFactory3)) factoryType = 3;
else if (IsEqualIID (riid, IID_IDXGIFactory4)) factoryType = 4;
else if (IsEqualIID (riid, IID_IDXGIFactory5)) factoryType = 5;
else if (IsEqualIID (riid, IID_IDXGIFactory6)) factoryType = 6;
else if (IsEqualIID (riid, IID_IDXGIFactory7)) factoryType = 7;
// ReSharper disable once CppDFAConstantConditions
if (factoryType >= 0) {
const IDXGIFactory *factory = static_cast<IDXGIFactory *> (*ppFactory);
const auto old = HookVtableFunction (&factory->lpVtbl->CreateSwapChain, CreateSwapChainWrap);
g_oldCreateSwapChain = old ? old : g_oldCreateSwapChain;
}
if (factoryType >= 2) {
const IDXGIFactory2 *factory = static_cast<IDXGIFactory2 *> (*ppFactory);
const auto old = HookVtableFunction (&factory->lpVtbl->CreateSwapChainForHwnd, CreateSwapChainForHwndWrap);
g_oldCreateSwapChainForHwnd = old ? old : g_oldCreateSwapChainForHwnd;
}
}
return hr;
}
static HRESULT WINAPI
D3D11CreateDeviceAndSwapChainWrap (IDXGIAdapter *pAdapter, const D3D_DRIVER_TYPE DriverType, const HMODULE Software, const UINT Flags,
const D3D_FEATURE_LEVEL *pFeatureLevels, const UINT FeatureLevels, const UINT SDKVersion,
/*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D11Device **ppDevice,
D3D_FEATURE_LEVEL *pFeatureLevel, ID3D11DeviceContext **ppImmediateContext) {
const HRESULT hr = g_origD3D11CreateDeviceAndSwapChain (pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion,
pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext);
if (ppSwapChain) {
if (FpsLimiterEnable) {
const auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, PresentWrap);
g_oldPresentWrap = old2 ? old2 : g_oldPresentWrap;
}
}
return hr;
}
void
Init () {
LogMessage (LogLevel::INFO, "Init Dxgi patches");
i32 fpsLimit = 120;
const auto configPath = std::filesystem::current_path () / "config.toml";
const std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
if (config_ptr) {
if (const auto graphics = openConfigSection (config_ptr.get (), "graphics"))
fpsLimit = static_cast<i32> (readConfigInt (graphics, "fpslimit", fpsLimit));
}
FpsLimiterEnable = fpsLimit > 0;
LogMessage (LogLevel::INFO, "Init DXGI patches");
FpsLimiterEnable = Config::ConfigManager::instance ().getGraphicsConfig ().fpslimit;
if (FpsLimiterEnable) {
FpsLimiter::Init (static_cast<float> (fpsLimit));
FpsLimiter::Init ();
MH_Initialize ();
MH_CreateHookApi (L"dxgi.dll", "CreateDXGIFactory", reinterpret_cast<LPVOID> (CreateDXGIFactoryWrap),
reinterpret_cast<void **> (&g_origCreateDXGIFactory));
MH_CreateHookApi (L"dxgi.dll", "CreateDXGIFactory2", reinterpret_cast<LPVOID> (CreateDXGIFactory2Wrap),
reinterpret_cast<void **> (&g_origCreateDXGIFactory2));
MH_CreateHookApi (L"d3d11.dll", "D3D11CreateDeviceAndSwapChain", reinterpret_cast<LPVOID> (D3D11CreateDeviceAndSwapChainWrap),
reinterpret_cast<void **> (&g_origD3D11CreateDeviceAndSwapChain));
MH_EnableHook (nullptr);
}
}
+3 -4
View File
@@ -10,14 +10,13 @@ namespace patches::FpsLimiter {
static LARGE_INTEGER PerformanceCount1;
static LARGE_INTEGER PerformanceCount2;
static bool bOnce1 = false;
static double targetFrameTime = 1000.0 / 60.0;
static double targetFrameTime = 1000.0 / 120.0;
static double t = 0.0;
static u32 i = 0;
void
Init (const float fpsLimit) {
if (fpsLimit > 0) LogMessage (LogLevel::INFO, "Init Fps Limiter");
targetFrameTime = 1000.0 / fpsLimit;
Init () {
LogMessage (LogLevel::INFO, "Init FPS Limiter");
}
void
+1 -1
View File
@@ -22,7 +22,7 @@ namespace Dxgi {
void Init ();
} // namespace Dxgi
namespace FpsLimiter {
void Init (float fpsLimit);
void Init ();
void Update ();
} // namespace FpsLimiter
namespace Audio {