Skip to content

Commit bc94009

Browse files
committed
Refactored frame rate limiter
1 parent b7a64b4 commit bc94009

File tree

6 files changed

+80
-33
lines changed

6 files changed

+80
-33
lines changed

Client/core/CCore.cpp

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,6 +1718,14 @@ void CCore::UpdateRecentlyPlayed()
17181718
CCore::GetSingleton().SaveConfig();
17191719
}
17201720

1721+
//
1722+
// Called just before GTA calculates frame time deltas
1723+
//
1724+
void CCore::OnGameTimerUpdate()
1725+
{
1726+
ApplyQueuedFrameRateLimit();
1727+
}
1728+
17211729
//
17221730
// Recalculate FPS limit to use
17231731
//
@@ -1793,34 +1801,47 @@ void CCore::ApplyFrameRateLimit(uint uiOverrideRate)
17931801

17941802
uint uiUseRate = uiOverrideRate != -1 ? uiOverrideRate : m_uiFrameRateLimit;
17951803

1796-
TIMING_GRAPH("Limiter");
1797-
17981804
if (uiUseRate < 1)
17991805
return DoReliablePulse();
18001806

1801-
if (m_DiagnosticDebug != EDiagnosticDebug::D3D_6732)
1802-
Sleep(1); // Make frame rate smoother maybe
1807+
// Apply previous frame rate if is hasn't been done yet
1808+
ApplyQueuedFrameRateLimit();
18031809

1804-
// Calc required time in ms between frames
1805-
const double dTargetTimeToUse = 1000.0 / uiUseRate;
1806-
1807-
while(true)
1808-
{
1809-
// See if we need to wait
1810-
double dSpare = dTargetTimeToUse - m_FrameRateTimer.Get();
1811-
if (dSpare <= 0.0)
1812-
break;
1813-
if (dSpare >= 2.0)
1814-
Sleep(1);
1815-
}
1816-
m_FrameRateTimer.Reset();
1810+
// Limit is usually applied in OnGameTimerUpdate
1811+
m_uiQueuedFrameRate = uiUseRate;
1812+
m_bQueuedFrameRateValid = true;
18171813

18181814
DoReliablePulse();
18191815

18201816
TIMING_GRAPH("FrameEnd");
18211817
TIMING_GRAPH("");
18221818
}
18231819

1820+
//
1821+
// Frame rate limit (wait) is done here.
1822+
//
1823+
void CCore::ApplyQueuedFrameRateLimit()
1824+
{
1825+
if (m_bQueuedFrameRateValid)
1826+
{
1827+
m_bQueuedFrameRateValid = false;
1828+
// Calc required time in ms between frames
1829+
const double dTargetTimeToUse = 1000.0 / m_uiQueuedFrameRate;
1830+
1831+
while(true)
1832+
{
1833+
// See if we need to wait
1834+
double dSpare = dTargetTimeToUse - m_FrameRateTimer.Get();
1835+
if (dSpare <= 0.0)
1836+
break;
1837+
if (dSpare >= 2.0)
1838+
Sleep(1);
1839+
}
1840+
m_FrameRateTimer.Reset();
1841+
TIMING_GRAPH("Limiter");
1842+
}
1843+
}
1844+
18241845
//
18251846
// DoReliablePulse
18261847
//

Client/core/CCore.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class CCore : public CCoreInterface, public CSingleton<CCore>
124124
void EnableChatInput(char* szCommand, DWORD dwColor);
125125
bool IsChatInputEnabled(void);
126126
bool ClearChat();
127+
void OnGameTimerUpdate(void);
127128

128129
// Screenshots
129130
void TakeScreenShot(void);
@@ -213,6 +214,7 @@ class CCore : public CCoreInterface, public CSingleton<CCore>
213214
uint GetFrameRateLimit(void) { return m_uiFrameRateLimit; }
214215
void RecalculateFrameRateLimit(uint uiServerFrameRateLimit = -1, bool bLogToConsole = true);
215216
void ApplyFrameRateLimit(uint uiOverrideRate = -1);
217+
void ApplyQueuedFrameRateLimit(void);
216218
void EnsureFrameRateLimitApplied(void);
217219
void SetClientScriptFrameRateLimit(uint uiClientScriptFrameRateLimit);
218220
void DoReliablePulse(void);
@@ -347,6 +349,8 @@ class CCore : public CCoreInterface, public CSingleton<CCore>
347349
uint m_uiClientScriptFrameRateLimit;
348350
uint m_uiFrameRateLimit;
349351
CElapsedTimeHD m_FrameRateTimer;
352+
uint m_uiQueuedFrameRate;
353+
bool m_bQueuedFrameRateValid;
350354
bool m_bWaitToSetNick;
351355
uint m_uiNewNickWaitFrames;
352356
EDiagnosticDebugType m_DiagnosticDebug;

Client/mods/deathmatch/logic/CClientGame.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3898,19 +3898,14 @@ void CClientGame::PostWorldProcessHandler(void)
38983898
m_pManager->GetPointLightsManager()->DoPulse();
38993899
m_pManager->GetObjectManager()->DoPulse();
39003900

3901-
// Update frame time slice
3902-
uint uiCurrentTick = GetTickCount32();
3903-
if (m_uiLastFrameTick)
3904-
{
3905-
m_uiFrameTimeSlice = uiCurrentTick - m_uiLastFrameTick;
3906-
m_uiFrameCount++;
3901+
double dTimeSlice = m_TimeSliceTimer.Get();
3902+
m_TimeSliceTimer.Reset();
3903+
m_uiFrameCount++;
39073904

3908-
// Call onClientPreRender LUA event
3909-
CLuaArguments Arguments;
3910-
Arguments.PushNumber(m_uiFrameTimeSlice);
3911-
m_pRootEntity->CallEvent("onClientPreRender", Arguments, false);
3912-
}
3913-
m_uiLastFrameTick = uiCurrentTick;
3905+
// Call onClientPreRender LUA event
3906+
CLuaArguments Arguments;
3907+
Arguments.PushNumber(dTimeSlice);
3908+
m_pRootEntity->CallEvent("onClientPreRender", Arguments, false);
39143909
}
39153910

39163911
void CClientGame::IdleHandler(void)

Client/mods/deathmatch/logic/CClientGame.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ class CClientGame
239239
void DoPulses(void);
240240
void DoPulses2(bool bCalledFromIdle);
241241

242-
uint GetFrameTimeSlice(void) { return m_uiFrameTimeSlice; }
243242
uint GetFrameCount(void) { return m_uiFrameCount; }
244243

245244
void HandleException(CExceptionInformation* pExceptionInformation);
@@ -766,9 +765,8 @@ class CClientGame
766765
unsigned long m_ulBigPacketBytesReceivedBase;
767766
CTransferBox* m_pBigPacketTransferBox;
768767

769-
uint m_uiFrameTimeSlice; // how long it took (in ms) to process the current frame
770-
uint m_uiLastFrameTick; // time at which the previous frame was processed
771-
uint m_uiFrameCount; // Frame counter
768+
CElapsedTimeHD m_TimeSliceTimer;
769+
uint m_uiFrameCount;
772770

773771
long long m_llLastTransgressionTime;
774772
SString m_strLastDiagnosticStatus;

Client/multiplayer_sa/CMultiplayerSA_Rendering.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,33 @@ void _declspec(naked) HOOK_WinLoop()
339339
}
340340
}
341341

342+
//////////////////////////////////////////////////////////////////////////////////////////
343+
//
344+
// CTimer::Update
345+
//
346+
// Just before GTA calculates frame time deltas
347+
//
348+
//////////////////////////////////////////////////////////////////////////////////////////
349+
#define HOOKPOS_CTimer_Update 0x561B10
350+
#define HOOKSIZE_CTimer_Update 6
351+
static const DWORD CONTINUE_CTimer_Update = 0x561B16;
352+
static void _declspec(naked) HOOK_CTimer_Update()
353+
{
354+
_asm
355+
{
356+
pushad
357+
}
358+
359+
g_pCore->OnGameTimerUpdate();
360+
361+
_asm
362+
{
363+
popad
364+
mov ecx,dword ptr ds:[0B7CB28h]
365+
jmp CONTINUE_CTimer_Update
366+
}
367+
}
368+
342369
//////////////////////////////////////////////////////////////////////////////////////////
343370
//
344371
// Photograph screen grab in windowed mode
@@ -624,6 +651,7 @@ void CMultiplayerSA::InitHooks_Rendering(void)
624651
EZHookInstall(Check_NoOfVisibleLods);
625652
EZHookInstall(Check_NoOfVisibleEntities);
626653
EZHookInstall(WinLoop);
654+
EZHookInstall(CTimer_Update);
627655
EZHookInstall(psGrabScreen);
628656
EZHookInstallChecked(CClouds_RenderSkyPolys);
629657
EZHookInstallChecked(RwCameraSetNearClipPlane);

Client/sdk/core/CCoreInterface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class CCoreInterface
172172
virtual void SetFakeLagCommandEnabled(bool bEnabled) = 0;
173173
virtual SString GetBlueCopyrightString(void) = 0;
174174
virtual bool ClearChat() = 0;
175+
virtual void OnGameTimerUpdate(void) = 0;
175176
};
176177

177178
class CClientTime

0 commit comments

Comments
 (0)