Add a better FPS limiter

This commit is contained in:
Skyth
2019-08-29 15:43:26 +03:00
parent ce6bb33ba8
commit 865e986246
10 changed files with 32 additions and 107 deletions
@@ -166,7 +166,7 @@ ConfigOptionBase* optionsArray[] = {
new DropdownOption(L"status_icons", PATCHES_SECTION, CONFIG_FILE, L"Status Icons:", L"Set the state of card reader and network status icons.", 3, std::vector<LPCWSTR>({ L"Default", L"Hidden", L"Error", L"OK", L"Partial OK" })),
new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Using the FPS limit requires the \"FPS Limiter\" component to be enabled.", 60, 0, INT_MAX),
new NumericOption(L"FPS.Limit", GRAPHICS_SECTION, CONFIG_FILE, L"FPS Limit:", L"Allows you to set a frame rate cap. Set to -1 to unlock the frame rate.", 60, -1, INT_MAX),
new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false),
};
@@ -213,8 +213,6 @@ ConfigOptionBase* componentsArray[] = {
new BooleanOption(L"debug_component", COMPONENTS_SECTION, COMPONENTS_FILE, L"Debug Component", L"Allows for changing game state (F4-F8 keys), using dev GUI and tests, and speeding up 2d animations/menus (hold SHIFT+TAB).", false, true),
new BooleanOption(L"fps_limiter", COMPONENTS_SECTION, COMPONENTS_FILE, L"FPS Limiter", L"Lets you set a framerate cap. The value of the limit is in the options tab.", false, true),
new BooleanOption(L"target_inspector", COMPONENTS_SECTION, COMPONENTS_FILE, L"Target Inspector", L"Enables hold transfers.", false, true),
};
@@ -7,6 +7,10 @@
#include <windows.h>
#include <iostream>
#include <chrono>
using namespace std::chrono;
int hookedCreateWindow(const char* title, void(__cdecl* exit_function)(int))
{
SetProcessDPIAware();
@@ -91,6 +95,21 @@ __int64 hookedParseParameters(int a1, __int64* a2)
return divaParseParameters(a1, a2);
}
time_point<high_resolution_clock> nextUpdate;
microseconds expectedFrameDuration(1000000 / nFpsLimit);
__int64 __fastcall hookedEngineUpdate(__int64 a1)
{
if (high_resolution_clock::now() < nextUpdate)
return 0;
const auto result = divaEngineUpdate(a1);
nextUpdate = high_resolution_clock::now() + expectedFrameDuration;
return result;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
@@ -109,6 +128,14 @@ BOOL APIENTRY DllMain(HMODULE hModule,
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)divaParseParameters, hookedParseParameters);
DetourTransactionCommit();
if (nFpsLimit > 0)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)divaEngineUpdate, hookedEngineUpdate);
DetourTransactionCommit();
}
}
return TRUE;
}
@@ -7,6 +7,7 @@
static int(__cdecl* divaCreateWindow)(const char* title, void(__cdecl* exitfunc)(int)) = (int(__cdecl*)(const char* title, void(__cdecl * exitfunc)(int)))0x140194D00;
__int64 (__fastcall* divaParseParameters)(int a1, __int64* a2) = (__int64(__fastcall*)(int a1, __int64* a2))0x140193630;
__int64(__fastcall* divaEngineUpdate)(__int64 a1) = (__int64(__fastcall*)(__int64 a1))0x140194D20;
uint8_t* fullScreenFlag = (uint8_t*)0x140EDA5D1;
DWORD* resolutionType = (DWORD*)0x140EDA5D4;
@@ -34,6 +35,8 @@ int nIntResHeight = GetPrivateProfileIntW(L"resolution", L"r.height", 720, CONFI
int nBitDepth = GetPrivateProfileIntW(L"resolution", L"bitdepth", 32, CONFIG_FILE);
int nRefreshRate = GetPrivateProfileIntW(L"resolution", L"refreshrate", 60, CONFIG_FILE);
int nFpsLimit = GetPrivateProfileIntW(L"graphics", L"fps.limit", 60, CONFIG_FILE);
// used to trick Optimus into switching to the NVIDIA GPU
HMODULE nvcudaModule = LoadLibraryW(L"nvcuda.dll");
// cuInit actually returns a CUresult, but we don't really care about it
@@ -12,7 +12,6 @@
#include "CameraController.h"
#include "DebugComponent.h"
#include "ScaleComponent.h"
#include "FPSLimiter.h"
#include "GameTargets/TargetInspector.h"
using ConfigFile = TLAC::FileSystem::ConfigFile;
@@ -42,7 +41,6 @@ namespace TLAC::Components
new FrameRateManager(),
new FastLoader(),
new ScaleComponent(),
new FPSLimiter(),
new StageManager(),
new CameraController(),
new DebugComponent(),
@@ -1,67 +0,0 @@
#include "FPSLimiter.h"
#include <Windows.h>
#include <chrono>
#include <thread>
#include <cmath>
#include <cstdio>
#include <tchar.h>
using dsec = std::chrono::duration<double>;
using seconds = std::chrono::seconds;
// this is pretty much just lybxlpsv's limiter, but removed from GLComponent
namespace TLAC::Components
{
using namespace std::chrono;
static std::chrono::time_point mBeginFrame = system_clock::now();
static std::chrono::time_point prevTimeInSeconds = time_point_cast<seconds>(mBeginFrame);
const LPCTSTR config_file_name = _T(".\\config.ini");
int fpsLimit = GetPrivateProfileIntW(L"graphics", L"fps.limit", 0, config_file_name);
FPSLimiter::FPSLimiter()
{
}
FPSLimiter::~FPSLimiter()
{
}
const char* FPSLimiter::GetDisplayName()
{
return "fps_limiter";
}
void FPSLimiter::Initialize(ComponentsManager* manager)
{
mBeginFrame = std::chrono::system_clock::now();
prevTimeInSeconds = std::chrono::time_point_cast<seconds>(mBeginFrame);
frameCountPerSecond = 0;
if(fpsLimit != 0)
printf("FPSLimiter fpsLimit: %d\n", fpsLimit);
}
// I assume this gets called once per frame... if not this won't work
void FPSLimiter::Update()
{
auto invFpsLimit = round<std::chrono::system_clock::duration>(dsec{ 1. / fpsLimit });
auto mEndFrame = mBeginFrame + invFpsLimit;
auto timeInSeconds = std::chrono::time_point_cast<seconds>(std::chrono::system_clock::now());
++frameCountPerSecond;
if (timeInSeconds > prevTimeInSeconds)
{
//printf("FPSLimiter::Update(): FPS: %d\n", frameCountPerSecond);
frameCountPerSecond = 0;
prevTimeInSeconds = timeInSeconds;
}
// This part keeps the frame rate.
if (fpsLimit > 19) // not sure why lyb used 19 here
std::this_thread::sleep_until(mEndFrame);
mBeginFrame = mEndFrame;
mEndFrame = mBeginFrame + invFpsLimit;
}
}
@@ -1,23 +0,0 @@
#pragma once
#include "EmulatorComponent.h"
#include <chrono>
using seconds = std::chrono::seconds;
namespace TLAC::Components
{
class FPSLimiter : public EmulatorComponent
{
public:
FPSLimiter();
~FPSLimiter();
virtual const char* GetDisplayName() override;
virtual void Initialize(ComponentsManager*) override;
virtual void Update() override;
private:
int frameCountPerSecond;
};
}
@@ -177,7 +177,6 @@
<ClInclude Include="Components\DebugComponent.h" />
<ClInclude Include="Components\EmulatorComponent.h" />
<ClInclude Include="Components\FastLoader.h" />
<ClInclude Include="Components\FPSLimiter.h" />
<ClInclude Include="Components\FrameRateManager.h" />
<ClInclude Include="Components\GameState.h" />
<ClInclude Include="Components\GameTargets\HoldState.h" />
@@ -238,7 +237,6 @@
<ClCompile Include="Components\DebugComponent.cpp" />
<ClCompile Include="Components\EmulatorComponent.cpp" />
<ClCompile Include="Components\FastLoader.cpp" />
<ClCompile Include="Components\FPSLimiter.cpp" />
<ClCompile Include="Components\FrameRateManager.cpp" />
<ClCompile Include="Components\GameTargets\TargetInspector.cpp" />
<ClCompile Include="Components\Input\InputEmulator.cpp" />
@@ -177,9 +177,6 @@
<ClInclude Include="Input\Xinput\XinputState.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Components\FPSLimiter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Components\GameTargets\HoldState.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -326,9 +323,6 @@
<ClCompile Include="Input\Xinput\XinputState.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Components\FPSLimiter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Components\GameTargets\TargetInspector.cpp">
<Filter>Source Files</Filter>
</ClCompile>